skip to content

Spring Cloud Gateway

The API gateway: routes and predicates, per-route and global filters, rate limiting, the reactive runtime, and the newer servlet variant. Interviewers ask what belongs in a gateway and what should stay in the services behind it.

part ofSpring Frameworkoverview, primer and where to startread it →
on this pageshow

explore

questions

30

What are GatewayFilter factories in Spring Cloud Gateway, and how do you configure one like AddRequestHeader on a route?

level: juniorimportance: must knowfreq 70%

answer

  1. Per-route predicates + filters
  2. Named factories: AddRequestHeader, RewritePath, StripPrefix
  3. Shortcut syntax maps to shortcutFieldOrder
  4. Adds header to DOWNSTREAM request
  5. WebFlux/Netty, reactive

basics

~10 s

They are reusable filters you attach to a single route to change its request or response. For example, AddRequestHeader=X-Env,prod adds that header to every request forwarded through that route.

solid answer

~40 s

In Spring Cloud Gateway a route has predicates (when it matches) and filters (what to do with the matched request). GatewayFilter factories are the named, parameterized building blocks for those per-route filters. You configure them declaratively, usually in application.yml under spring.cloud.gateway.routes[].filters. Built-in examples include AddRequestHeader, RewritePath, StripPrefix, RedirectTo and SetStatus. Each factory reads its arguments (e.g. AddRequestHeader=X-Request-Env, prod) and produces a GatewayFilter that runs when the route matches. AddRequestHeader specifically adds a header to the request sent to the downstream service, not to the client's original view. Because filters are per-route, the same factory can be reused with different arguments on different routes, which keeps routing configuration declarative and composable.

code

kotlin · 10 lines
kotlin
// application.yml equivalent expressed via the Java/Kotlin route DSL
@Bean
fun routes(builder: RouteLocatorBuilder): RouteLocator =
    builder.routes()
        .route("users-route") { r ->
            r.path("/api/users/**")
                .filters { f -> f.addRequestHeader("X-Request-Env", "prod") }
                .uri("http://users-service:8080")
        }
        .build()

go deeper

for a junior

Should know filters are per-route and AddRequestHeader adds a header to the forwarded request.

for a middle

Should know shortcut vs expanded syntax and Add vs Set semantics.

for a senior

Should relate factories to the GatewayFilter/predicate model and reactive stack.

for a principal

Frames filters as declarative edge policy and knows the factory/shortcutFieldOrder mechanism.

**Spring Cloud Gateway** is an API gateway built on Spring WebFlux and Project Reactor (non-blocking, runs on Netty). It routes incoming requests to downstream services. A **route** has three parts: an id, a set of **predicates** (conditions like path, host, method that decide whether the route matches), and a set of **filters** (logic that mutates the request/response as it passes through). A **GatewayFilter factory** is a component that produces a `GatewayFilter` for one route. Each built-in factory is named `<Name>GatewayFilterFactory` and is referenced in config by its short name (`AddRequestHeader`, `RewritePath`, `StripPrefix`, `RedirectTo`, `SetStatus`, etc.). The factory pattern lets you parameterize the filter: you give it arguments and it returns a configured filter instance. **Typical YAML configuration:** ```yaml spring: cloud: gateway: routes: - id: users-route uri: http://users-service:8080 predicates: - Path=/api/users/** filters: - AddRequestHeader=X-Request-Env, prod ``` Here `AddRequestHeader=X-Request-Env, prod` means: for any request matching this route, add the header `X-Request-Env: prod` **to the request that is forwarded downstream**. This is the key semantic — it modifies the outbound (proxied) request, so the downstream service sees the header. The original client never set it and does not see it added to their own copy. **Shortcut vs full syntax.** The compact form `AddRequestHeader=X-Request-Env, prod` is a *shortcut*; the factory declares a `shortcutFieldOrder()` so positional args map to config fields. The equivalent expanded form is: ```yaml - name: AddRequestHeader args: name: X-Request-Env value: prod ``` **Per-route vs global.** GatewayFilter factories are per-route. A different mechanism, `GlobalFilter`, applies to every route (that is a separate concern and out of scope here). You can attach many filters to one route; they run in a chain. **When to use.** Use built-in GatewayFilter factories for common edge concerns without writing code: injecting headers for downstream services, rewriting/stripping path prefixes so the gateway's public path differs from the backend's internal path, issuing redirects, or overriding response status. **Gotchas.** AddRequestHeader *adds* (it does not replace) — a duplicate header can result if the client already sent one; use `SetRequestHeader` to overwrite. YAML values with commas or special characters may need quoting. The value supports property placeholders and, since it produces a request header, it affects only the proxied request.

  • What is the difference between AddRequestHeader and SetRequestHeader?
    AddRequestHeader appends a header value (can create duplicates if one already exists); SetRequestHeader overwrites/replaces any existing value for that header name.
  • Does AddRequestHeader modify the response the client receives?
    No. It modifies the request forwarded to the downstream service. For response headers you'd use AddResponseHeader.

saying these in an interview costs you the question

  • Thinking AddRequestHeader modifies the client's original request or the response
  • Confusing per-route GatewayFilter factories with GlobalFilters
  • Believing AddRequestHeader replaces an existing header (it appends)

context

open as a page

What is a GlobalFilter in Spring Cloud Gateway, and how does it differ from a GatewayFilter?

level: juniorimportance: must knowfreq 70%

basics

~20 s

A GlobalFilter runs on every route automatically. A GatewayFilter is configured per route. Both intercept the request/response; the difference is scope — global applies to all routes, gateway filters only to routes you attach them to.

open as a page

What is the RequestRateLimiter filter in Spring Cloud Gateway, and what happens when a client exceeds the limit?

level: juniorimportance: must knowfreq 60%

basics

~20 s

RequestRateLimiter is a built-in gateway filter that caps how many requests a client can make in a time window. When the client sends too many, the gateway rejects the extra requests with HTTP 429 Too Many Requests instead of forwarding them.

open as a page

Why does Spring Cloud Gateway run on the reactive WebFlux/Netty stack instead of the Spring MVC servlet stack?

level: juniorimportance: must knowfreq 70%

basics

~20 s

A gateway spends its time waiting on downstream services, not computing. WebFlux on Netty handles many waiting requests with a few non-blocking threads, so the gateway scales far better than a servlet with one blocking thread per request.

open as a page

What is a route in Spring Cloud Gateway, and what are its parts?

level: juniorimportance: must knowfreq 70%

basics

~20 s

A route is the basic building block: an id, a destination uri, a set of predicates that decide if a request matches, and optional filters. If all predicates match, the request is forwarded to the uri.

open as a page

What is Spring Cloud Gateway Server MVC, and how does it differ from the reactive Gateway?

level: juniorimportance: must knowfreq 55%

basics

~10 s

It is the API gateway built on blocking Spring MVC (servlet stack) instead of reactive WebFlux/Netty. It runs on a servlet container with thread-per-request and proxies calls using a blocking RestClient.

open as a page

How is the order of filters determined in Spring Cloud Gateway, and how does implementing Ordered affect a GlobalFilter?

level: middleimportance: must knowfreq 65%

basics

~20 s

Filters are sorted by their order value (lower runs first on the way in). A GlobalFilter can implement Ordered or use @Order to control its position. The built-in routing filters use the lowest precedence so they run last.

open as a page

What is a KeyResolver in Spring Cloud Gateway rate limiting, and how would you implement per-user and per-IP resolvers?

level: middleimportance: must knowfreq 55%

basics

~20 s

A KeyResolver returns a key that identifies which rate-limit bucket a request belongs to. Requests with the same key share one bucket. For per-user you return the user id/principal; for per-IP you return the client's IP address.

open as a page

In RedisRateLimiter, what do replenishRate and burstCapacity mean, and how does the token-bucket algorithm use them?

level: middleimportance: must knowfreq 65%

basics

~20 s

replenishRate is how many tokens (requests) are added to the bucket per second — the steady allowed rate. burstCapacity is the maximum tokens the bucket can hold — the biggest short burst allowed. Each request spends one token; an empty bucket means 429.

open as a page

Walk through the reactive request pipeline in Spring Cloud Gateway: how does an incoming request flow through ServerWebExchange and the GatewayFilterChain to become a proxied call?

level: middleimportance: must knowfreq 60%

basics

~20 s

A handler mapping matches the request to a route, then a filter chain of global + route filters runs. Each filter can modify the request before calling the next, and modify the response after. A routing filter actually proxies the call; the whole flow returns a Mono.

open as a page

Walk through the Path, Host, Method, Header, and Query predicate factories — what each matches and how they combine.

level: middleimportance: must knowfreq 60%

basics

~20 s

Path matches the URL path (Ant-style / PathPattern). Host matches the Host header. Method matches the HTTP verb. Header matches a header's presence/regex. Query matches a query parameter's presence/regex. Multiple predicates on one route are AND-ed.

open as a page

How do you define a route programmatically in Gateway Server MVC using the RouterFunctions DSL?

level: middleimportance: must knowfreq 50%

basics

~10 s

Declare a RouterFunction<ServerResponse> bean built with GatewayRouterFunctions.route(id), pairing a predicate (like path("/api/**")) with the http() handler that names the upstream URI, then call build().

open as a page

Explain the pre and post phases of a GatewayFilter and how you mutate the ServerWebExchange request versus response in each.

level: seniorimportance: must knowfreq 55%

basics

~20 s

A GatewayFilter can run logic before forwarding (pre) and after the response comes back (post). In the pre phase you mutate the request via exchange.mutate(); in the post phase (inside .then(...)) you touch the response after chain.filter completes.

open as a page

Explain GatewayFilterChain delegation: how does chain.filter(exchange) work and how do you add pre- and post-processing in a GlobalFilter?

level: seniorimportance: must knowfreq 60%

basics

~20 s

Each filter does its pre-work, then calls chain.filter(exchange) to pass control to the next filter, returning a Mono. To do post-work, chain .then(...) or .doFinally(...) onto that Mono so it runs after downstream filters complete.

open as a page

The reactive gateway runs on a small Netty event-loop thread pool. What are the consequences of blocking inside a filter, and how do you handle work that must block?

level: seniorimportance: must knowfreq 45%

basics

~20 s

Netty has only a few event-loop threads (about one per core). If a filter blocks — a JDBC call, Thread.sleep, a blocking HTTP client — it parks one of those threads, so many requests stall at once. Offload blocking work to a bounded elastic scheduler, or avoid it.

open as a page

Contrast RedirectTo and SetStatus. What does each do to the response and request flow?

level: middleimportance: should knowfreq 45%

basics

~20 s

SetStatus just overrides the HTTP status code of the response the client gets, while still forwarding to the downstream. RedirectTo short-circuits the route: it returns a redirect (status + Location header) to the client and does not forward the request downstream.

open as a page

Compare StripPrefix and RewritePath. When would you choose one over the other?

level: middleimportance: should knowfreq 60%

basics

~20 s

Both change the path sent downstream. StripPrefix removes a fixed number of leading path segments. RewritePath uses a regex to transform the path into any shape. Use StripPrefix for simple prefix removal, RewritePath when you need pattern-based rewriting.

open as a page

How do you define the same route in YAML versus the Java RouteLocatorBuilder DSL?

level: middleimportance: should knowfreq 55%

basics

~10 s

In YAML you list routes under spring.cloud.gateway.routes with shortcut predicates like Path=/api/. In Java you declare a RouteLocator @Bean using RouteLocatorBuilder, chaining .route(id, r -> r.path("/api/").uri("...")). Both produce the same routes.

open as a page

What do NettyRoutingFilter and ForwardRoutingFilter do, and how does the gateway decide which one performs the proxied call?

level: seniorimportance: should knowfreq 45%

basics

~20 s

They are the terminal GlobalFilters that actually make the call. NettyRoutingFilter proxies http/https URIs using a Netty HTTP client. ForwardRoutingFilter handles forward: URIs by dispatching locally in the same gateway app. The URI scheme decides which runs.

open as a page

How does RedisRateLimiter enforce limits atomically across gateway instances, and what response headers and denial behavior does it produce?

level: seniorimportance: should knowfreq 40%

basics

~20 s

It runs a Redis Lua script that atomically refills the token bucket by elapsed time and decrements it, so concurrent gateway nodes can't race. On success it adds X-RateLimit-* headers; when tokens run out it sets HTTP 429 and stops the request.

open as a page

How does Spring Cloud Gateway proxy request and response bodies in a backpressure-aware, streaming way rather than buffering entire payloads?

level: seniorimportance: should knowfreq 40%

basics

~20 s

Bodies flow as a stream of DataBuffer chunks (a Flux), not one big blob. The gateway passes those chunks through reactor-netty, which only pulls more from the source when the destination is ready, so a slow client or downstream naturally throttles the fast side.

open as a page

Explain the After/Before/Between temporal predicates and how Path/Host capture variables for downstream use.

level: seniorimportance: should knowfreq 40%

basics

~20 s

After, Before, and Between compare the current time to a ZonedDateTime: After matches requests after it, Before matches before it, Between matches within a window. Path and Host patterns can capture named variables (like {segment}) that filters can reuse.

open as a page

How do HandlerFilterFunctions work in Gateway Server MVC, and how do before/after/filter differ?

level: seniorimportance: should knowfreq 42%

basics

~10 s

Filters are HandlerFilterFunctions that wrap the handler. before-filters transform the ServerRequest, after-filters transform the ServerResponse, and a full filter wraps both sides and can short-circuit. Add them from factories like BeforeFilterFunctions and AfterFilterFunctions.

open as a page

How does RestClient-based proxying work in Gateway Server MVC, and how is the proxy client configured?

level: seniorimportance: should knowfreq 35%

basics

~20 s

The terminal http() handler forwards the incoming request to the upstream URI using a blocking RestClient: it copies method, path, headers and body, calls the backend synchronously, and streams the response back as a ServerResponse.

open as a page

How would you implement a custom GatewayFilter factory, and what are the key extension points (config binding, shortcut args, ordering)?

level: principalimportance: should knowfreq 35%

basics

~10 s

Extend AbstractGatewayFilterFactory<Config> with a nested Config POJO, register it as a @Component whose class name ends in GatewayFilterFactory, implement apply(config) to return the GatewayFilter, and override shortcutFieldOrder() to enable the compact YAML syntax.

open as a page

You need cross-cutting timing metrics plus a filter that runs immediately before the downstream call. How do you design the ordering, and what constraints do the terminal routing filters impose?

level: principalimportance: should knowfreq 30%

basics

~20 s

Put the timing filter at a very low order so it wraps everything, doing pre-work first and post-work last via .then(). Any "just before the call" work must also go pre-side at a high order (near, but before, LOWEST_PRECEDENCE), because the routing filter is terminal and won't run anything after it on the pre path.

open as a page

As an architect, how would you design a multi-tier rate-limiting strategy at the gateway, and what are the failure and fairness trade-offs of the RedisRateLimiter approach?

level: principalimportance: should knowfreq 25%

basics

~20 s

Layer limits: coarse per-IP limits on unauthenticated routes and finer per-user/per-tenant limits on authenticated APIs, sized to each backend's capacity. Weigh Redis as a shared dependency (latency, single point of failure, fail-open vs fail-closed) and per-key fairness against real client identity.

open as a page

Spring Cloud Gateway ships both a reactive (WebFlux/Netty) server and a servlet (Spring MVC) server. As an architect, how do you decide which to run, and what does the reactive stack actually buy you?

level: principalimportance: should knowfreq 30%

basics

~20 s

The reactive gateway scales huge concurrency with few threads and streams bodies with backpressure — ideal for high fan-out, slow backends, or streaming. The MVC gateway uses familiar blocking code and libraries. Choose reactive for scale/streaming; MVC when the team relies on blocking stacks and concurrency is moderate.

open as a page

When several routes could match a request, how does the gateway decide which one wins, and how is route order controlled?

level: principalimportance: should knowfreq 35%

basics

~20 s

The RoutePredicateHandlerMapping evaluates routes in order and picks the first whose combined predicate matches. Routes are sorted by their order field (lower = higher priority); if unset, they keep their declared order. First match wins — later routes aren't tried.

open as a page

As an architect, when would you choose Gateway Server MVC over the reactive gateway, and what are the tradeoffs?

level: principalimportance: should knowfreq 30%

basics

~10 s

Choose MVC when your stack is blocking or your team wants the familiar servlet/MVC model — especially with virtual threads. Choose reactive for maximum non-blocking concurrency. The tradeoff is thread-per-request simplicity vs event-loop scalability.

open as a page