工作流程示意图
下图概括介绍了 Spring Cloud Gateway
的工作流程:
客户端向 Spring Cloud Gateway
发出请求。如果网关 HandlerMapping
确定请求与路由匹配,则将其发送到网关 WebHandler
。Handler
通过特定的过滤器链来将请求发送到下游服务, 过滤器中间用虚线的原因是过滤器可以在发送代理请求之前和之后运行特定逻辑。顺序是所有“前置”过滤器逻辑都已执行,然后发出代理请求,后将运行“后置”过滤器逻辑
处理请求流程
要摸清请求流程,首先要找到请求入口,网关请求入口在 DispatcherHandler
,当收到请求后,会执行 handle
方法
根据请求获取handle
当请求到达 DispatcherHandler
时,向 handlerMappings
获取处理请求的 handler
,handlerMappings
就是所有路由的映射,包括 Controller
接口、一些系统自带的接口及下游服务,如果没找到则直接返回 404
遍历handlerMappings获取handle源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| public Mono<Void> handle(ServerWebExchange exchange) { if (this.handlerMappings == null) { return createNotFoundError(); } if (CorsUtils.isPreFlightRequest(exchange.getRequest())) { return handlePreFlight(exchange); } return Flux.fromIterable(this.handlerMappings) .concatMap(mapping -> mapping.getHandler(exchange)) .next() .switchIfEmpty(createNotFoundError()) .flatMap(handler -> invokeHandler(exchange, handler)) .flatMap(result -> handleResult(exchange, result)); }
|
可以看到 handlerMappings
其实是一个列表,其中有保存 Controller
接口的 RequestMappingHandlerMapping
,还有保存服务路由的 RoutePredicateHandlerMapping
我们也可以定义自己 handlerMapping
,通过继承 AbstractHandlerMapping
,重写获取handle的方法 getHandlerInternal
,这里可以根据请求路径等匹配,然后返回handle处理器就是用于处理请求的类
根据请求预设规则匹配路由
RoutePredicateHandlerMapping#getHandlerInternal
方法返回的是具体的处理器 handle
,这里handle其实是同一个 webHandler
,并不会根据路径接口或者路由的服务变化, 方法里的逻辑是匹配路由,然后把路由放到请求上下文中
首先判断是不是访问管理端口的请求,是的话则不处理。接着根据请求查找路由,查找逻辑是判断当前请求是否符合预设的匹配规则。 默认情况下,通过 DiscoveryClient
创建的每个网关路由都会有一个默认的匹配规则:/serviceId/**
,这个 serviceId
是 DiscoveryClient
中服务的ID 也就是根据访问服务名来匹配对应的路由。找到路由后返回网关路由特定处理器 webHandler
,对应上面图中的 Gateway Web Handler
DiscoveryClient:是用于从注册中心获取服务路由
webHandler: 即 org.springframework.cloud.gateway.handler.FilteringWebHandler
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| protected Mono<?> getHandlerInternal(ServerWebExchange exchange) { if (this.managementPortType == DIFFERENT && this.managementPort != null && exchange.getRequest().getURI().getPort() == this.managementPort) { return Mono.empty(); } exchange.getAttributes().put(GATEWAY_HANDLER_MAPPER_ATTR, getSimpleName()); return lookupRoute(exchange) .flatMap((Function<Route, Mono<?>>) r -> { exchange.getAttributes().remove(GATEWAY_PREDICATE_ROUTE_ATTR); if (logger.isDebugEnabled()) { logger.debug("Mapping [" + getExchangeDesc(exchange) + "] to " + r); } exchange.getAttributes().put(GATEWAY_ROUTE_ATTR, r); return Mono.just(webHandler); }).switchIfEmpty(Mono.empty().then(Mono.fromRunnable(() -> { exchange.getAttributes().remove(GATEWAY_PREDICATE_ROUTE_ATTR); if (logger.isTraceEnabled()) { logger.trace("No RouteDefinition found for [" + getExchangeDesc(exchange) + "]"); } }))); }
protected Mono<Route> lookupRoute(ServerWebExchange exchange) { return this.routeLocator.getRoutes() .concatMap(route -> Mono.just(route).filterWhen(r -> { exchange.getAttributes().put(GATEWAY_PREDICATE_ROUTE_ATTR, r.getId()); return r.getPredicate().apply(exchange); }) .doOnError(e -> logger.error( "Error applying predicate for route: " + route.getId(), e)) .onErrorResume(e -> Mono.empty())) .next() .map(route -> { if (logger.isDebugEnabled()) { logger.debug("Route matched: " + route.getId()); } validateRoute(route, exchange); return route; }); }
|
webHandler处理路由
网关的处理步骤和springMVC一样,由 HandlerAdapter
适配器处理,适配器也是一个列表,通过重写 supports
方法来判断是否支持该处理器。对于路由请求处理器webHandler来说,对应的适配器为 org.springframework.web.reactive.result.SimpleHandlerAdapter
。
1 2 3 4 5 6 7 8 9 10 11
| private Mono<HandlerResult> invokeHandler(ServerWebExchange exchange, Object handler) { if (this.handlerAdapters != null) { for (HandlerAdapter handlerAdapter : this.handlerAdapters) { if (handlerAdapter.supports(handler)) { return handlerAdapter.handle(exchange, handler); } } } return Mono.error(new IllegalStateException("No HandlerAdapter: " + handler));
|
经过适配器最终会调用 FilteringWebHandler#handle
方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| 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);
if (logger.isDebugEnabled()) { logger.debug("Sorted gatewayFilterFactories: " + combined); }
return new DefaultGatewayFilterChain(combined).filter(exchange); }
|
Handler
会使用一系列过滤器来处理,最终将请求发送到下游服务,其中过滤器又分全局过滤器和网关过滤器,全局过滤器所有路由都会执行,一般我们的鉴权、限流逻辑就是通过自定义全局过滤器来实现的,通过实现 GlobalFilter
接口来定义,也可以通过配置项 spring.cloud.gateway.default-filters
来配置,
只针对注册中心来的路由还可以通过配置 spring.cloud.gateway.discovery.locator.filters
。网关处理器只对这个网关有效,也可以针对每个网关单独配置 spring.cloud.gateway.routes[0].filters
在默认情况下,网关会为通过 DiscoveryClient
创建的路由定义一个断言和过滤器:
- 默认断言是使用
/serviceId/**
定义的path断言,其中serviceId是 DiscoveryClient
中服务的ID
- 默认的过滤器使用正则表达式
/serviceId/(?<remaining>.*)
和替换的 /${remaining}
进行重写,用于在请求之前从路径中截取掉serviceId
最终请求会在 NettyRoutingFilter
中发出