Spring Cloud Gateway Deep Dive: Request Flow, Handlers & Filters
This article explains the internal execution process of Spring Cloud Gateway, detailing how DispatcherHandler locates HandlerMapping, creates FilteringWebHandler, selects SimpleHandlerAdapter, builds and runs the filter chain—including core filters like RouteToRequestUrlFilter and NettyRoutingFilter—and transforms incoming URLs to their target destinations.
Gateway request execution flow consists of several steps:
1. Core processing class DispatcherHandler
public class DispatcherHandler implements WebHandler {
public Mono<Void> handle(ServerWebExchange exchange) {
// ...
return Flux.fromIterable(this.handlerMappings)
// find suitable HandlerMapping
.concatMap(mapping -> mapping.getHandler(exchange))
.next()
.switchIfEmpty(createNotFoundError())
.flatMap(handler -> invokeHandler(exchange, handler))
.flatMap(result -> handleResult(exchange, result));
}
}2. Find HandlerMapping object
The routing request resolves to RoutePredicateHandlerMapping, which stores the matched route in the exchange attributes and returns Mono.just(webHandler) where the webHandler is FilteringWebHandler.
@Bean
public FilteringWebHandler filteringWebHandler(List<GlobalFilter> globalFilters) {
return new FilteringWebHandler(globalFilters);
}3. Find HandlerAdapter object
The FilteringWebHandler (a WebHandler subclass) is finally handled by SimpleHandlerAdapter:
public class SimpleHandlerAdapter implements HandlerAdapter {
@Override
public boolean supports(Object handler) {
return WebHandler.class.isAssignableFrom(handler.getClass());
}
@Override
public Mono<HandlerResult> handle(ServerWebExchange exchange, Object handler) {
WebHandler webHandler = (WebHandler) handler;
Mono<Void> mono = webHandler.handle(exchange);
return mono.then(Mono.empty());
}
}4. Execute FilteringWebHandler
public class FilteringWebHandler implements WebHandler {
public Mono<Void> handle(ServerWebExchange exchange) {
Route route = exchange.getRequiredAttribute(GATEWAY_ROUTE_ATTR);
List<GatewayFilter> gatewayFilters = route.getFilters();
List<GatewayFilter> combined = new ArrayList<>(this.globalFilters);
combined.addAll(gatewayFilters);
AnnotationAwareOrderComparator.sort(combined);
return new DefaultGatewayFilterChain(combined).filter(exchange);
}
}5. Core filters
Key filters include RouteToRequestUrlFilter, which builds the target URL from route configuration, and NettyRoutingFilter, which performs the actual network request using a Netty HttpClient. Example configuration and URL transformation are shown.
spring:
cloud:
gateway:
enabled: true
httpclient:
connect-timeout: 10000
response-timeout: 5000
discovery:
locator:
enabled: true
lowerCaseServiceId: true
default-filters:
- StripPrefix=1
routes:
- id: R001
uri: http://localhost:8787
predicates:
- Path=/api-1/**,/api-2/**
metadata:
akf: "dbc"
connect-timeout: 10000
response-timeout: 5000Accessing http://localhost:8088/api-1/demos is transformed to http://localhost:8787/demos, and the final URL is stored in the exchange attributes.
Note: the StripPrefixGatewayFilterFactory#apply filter runs after the above filters.
Additional core filter implementation:
public class NettyRoutingFilter implements GlobalFilter {
private final HttpClient httpClient;
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
URI requestUrl = exchange.getRequiredAttribute(GATEWAY_REQUEST_URL_ATTR);
Route route = exchange.getAttribute(GATEWAY_ROUTE_ATTR);
Flux<HttpClientResponse> responseFlux = getHttpClient(route, exchange)
.request(method).uri(url).send((req, nettyOutbound) ->
nettyOutbound.send(request.getBody().map(this::getByteBuf)))
.responseConnection((res, connection) -> {
// handle response, headers, status, timeouts, etc.
return Mono.just(res);
});
Duration responseTimeout = getResponseTimeout(route);
if (responseTimeout != null) {
responseFlux = responseFlux.timeout(responseTimeout,
Mono.error(new TimeoutException("Response took longer than timeout: " + responseTimeout)))
.onErrorMap(TimeoutException.class,
th -> new ResponseStatusException(HttpStatus.GATEWAY_TIMEOUT, th.getMessage(), th));
}
return responseFlux.then(chain.filter(exchange));
}
// getHttpClient implementation omitted for brevity
}End of flow.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Spring Full-Stack Practical Cases
Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
