服务网关GateWay原理

embedded/2024/12/23 5:08:38/

文章目录

      • 自动装配核心类
      • GatewayAutoConfiguration
      • DispatcherHandler
      • 请求处理阶段
          • apply方法
          • httpHandler#handle方法
          • WebHandler#handle方法
          • DispatchHanlder#handle方法
          • 第一步 getHandler获取请求映射
          • 第二步 invokeHandler 请求适配
          • 第三步 handleResult请求处理
          • 总结

上一篇博文我们讲解了GateWay的基础用法 服务网关,接下来我们就一起基于源码梳理一下GateWay的核心流程。本篇博文基于 Spring cloud gateWay 2.2.5RELEASE版本进行学习

先贴上官网中gateway整合请求完成流程:
在这里插入图片描述

自动装配核心类

GateWay是基于SpringBoot自动装配在我们的项目中启作用的。有关自动装配的文章参考:springBoot的自动装配。所以基于我们引入的依赖spring-cloud-starter-gateway来作为入口。入口没有配置自动装配类的文件spring.factories,所以继续往下探究。

spring-cloud-starter-gateway引入了

  • spring-cloud-gateway-core 网关核心
  • spring-boot-starter-webflux 响应式编程依赖
  • spring-cloud-starter-loadbalancer 从注册中心获取服务的负载

webflux、loadbalance都是辅助GateWay的组件,所以继续往spring-cloud-gateway-core里查找,找到对应的spring.factories

自动装配类作用
GatewayClassPathWarningAutoConfigurationwebFlux没有引入的警告
GatewayAutoConfiguration网关自动装配核心
GatewayHystrixCircuitBreakerAutoConfiguration熔断器自动装配
GatewayResilience4JCircuitBreakerAutoConfiguration在3.0.0.RELEASE中,已经被GatewayReactiveLoadBalancerClientAutoConfiguration替代
GatewayResilience4JCircuitBreakerAutoConfiguration实现ReactiveLoadBalancerClientFilter
GatewayLoadBalancerClientAutoConfiguration引入ribbon时的负载均衡自动装配
GatewayNoLoadBalancerClientAutoConfiguration没有引入ribbon时的负载均衡自动装配
GatewayMetricsAutoConfiguration整合监控相关,提供监控指标。与actuators配合
GatewayRedisAutoConfiguration与redis结合,可使用到限流等方面
GatewayDiscoveryClientAutoConfiguration与服务发现组件进行结合起作用
SimpleUrlHandlerMappingGlobalCorsAutoConfiguration支持cors-configurations配置,对CORS请求预检
GatewayReactiveLoadBalancerClientAutoConfigurationReactiveLoadBalancerClientFilter实例化
LoadBalancerClientFilter与ReactiveLoadBalancerClientFilter只会实例化一个

GatewayAutoConfiguration

gateway的自动装配类中比较重要的是 GatewayAutoConfiguration, 它负责很多bean的初始化,它的类声明如下:

@Configuration(proxyBeanMethods = false
)
@ConditionalOnProperty(name = {"spring.cloud.gateway.enabled"},matchIfMissing = true
)
@EnableConfigurationProperties
@AutoConfigureBefore({HttpHandlerAutoConfiguration.class, WebFluxAutoConfiguration.class})
@AutoConfigureAfter({GatewayLoadBalancerClientAutoConfiguration.class, GatewayClassPathWarningAutoConfiguration.class})
@ConditionalOnClass({DispatcherHandler.class})
public class GatewayAutoConfiguration {//.....
}
  • 配置类:@Configuration声明GatewayAutoConfiguration是一个配置类,proxyBeanMethods声明配置类不会被代理提高性能。
  • 声明在配置spring.cloud.gateway.enabled值为true时加载GatewayAutoConfiguration配置,默认值是true。
  • 在HttpHandlerAutoConfiguration 和 WebFluxAutoConfiguration之前加载
  • 在GatewayLoadBalancerClientAutoConfiguration 和 GatewayClassPathWarningAutoConfiguration之后加载。
  • 注解@ConditionalOnClass作用只有DispatcherHandler类对应的bean实例存在才启动该配置

重要的bean实例

自动配置类GatewayAutoConfiguration在内部初始化了很多bean,列举几个重要的如下:

bean对象作用
PropertiesRouteDefinitionLocator用于从配置文件(yml/properties)中读取路由配置信息
RouteDefinitionLocator把 RouteDefinition 转化为 Route
RoutePredicateHandlerMapping类似于 mvc 的HandlerMapping,不过这里是 Gateway实现的。用于匹配对应的请求route
GatewayProperties网关的配置信息封装在 GatewayProperties 对象中
AfterRoutePredicateFactory各种路由断言工厂,正是这些断言工厂在启动时已经生成对应的bean
RetryGatewayFilterFactory各种 Gateway 过滤器,正是这些过滤器在启动时已经生成对应的bean
GlobalFilter全局过滤器
DispatcherHandleGateWay服务请求分发的入口类(该类不是GatewayAutoConfiguration实现化得到)
CachingRouteLocator基于缓存的路由定位器

在这里插入图片描述

DispatcherHandler

​ 该类实现了WebHandler 说明其是webFulx响应编程的请求分发的入口。

​ 实现了ApplicationContextAware,说明在spring容器启动时侯会通过setApplicationContext初始化器内部依赖。

public class DispatcherHandler implements WebHandler, ApplicationContextAware {//构造器public DispatcherHandler(ApplicationContext applicationContext) {this.initStrategies(applicationContext);}//容器启动后调用public void setApplicationContext(ApplicationContext applicationContext) {this.initStrategies(applicationContext);}//初始化该类的handlerMappings、handlerAdapters、resultHandlers组件protected void initStrategies(ApplicationContext context) {//获取所有符合条件的HandlerMappingMap<String, HandlerMapping> mappingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);ArrayList<HandlerMapping> mappings = new ArrayList(mappingBeans.values());AnnotationAwareOrderComparator.sort(mappings);this.handlerMappings = Collections.unmodifiableList(mappings);//获取所有符合条件的HandlerAdapterMap<String, HandlerAdapter> adapterBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);this.handlerAdapters = new ArrayList(adapterBeans.values());AnnotationAwareOrderComparator.sort(this.handlerAdapters);//获取所有符合条件的HandlerResultHandlerMap<String, HandlerResultHandler> beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerResultHandler.class, true, false);this.resultHandlers = new ArrayList(beans.values());AnnotationAwareOrderComparator.sort(this.resultHandlers);}//省略部分代码...
}

GateWay采用的是webFlux的响应式编程,其整个流程与spring mvc 类似。

框架gateWaymvc
请求分发DispatcherHandlerDispatcherServlet
请求映射HandlerMappingHandlerMapping
请求适配HandlerAdapterHanderAdapter
请求处理HandlerResultHandlerHander
  • DispatcherHandler:请求处理的调度中心。
  • HandlerMapping:将请求映射到处理程序handler对象。
  • HandlerAdapter:用来适配处理程序,也用来将DispatcherHandler与相应的真正对请求进行处理的handler解耦。
  • HandlerResultHandler:用来处理相应的处理程序的返回结果的程序。

HandlerMapping

在这里插入图片描述

创建DispatcherHandler实例化了6个HandlerMapping

HandlerMapping 请求映射作用
WebFluxEndpointHandlerMapping负责将HTTP请求映射到相应的端点处理器(webFlux)
ControllerEndpointHandlerMapping负责将对/actuator端点的请求映射到相应的端点处理器。
RouterFunctionMapping负责将接收到的请求与路由规则进行匹配
RequestMappingHandlerMapping负责用于复杂的路由配置
RoutePredicateHandlerMapping负责为Gateway的路由断言机制定制的HandlerMapping
SimpleUrlHandlerMapping用于简单的url匹配

HandlerAdapter
在这里插入图片描述

创建DispatcherHandler实例化了3个HandlerAdapter

HandlerAdapter请求适配作用
RequestMappingHandlerAdapter负责将HTTP请求映射到相应的端点处理器(webFlux)
HandlerFunctionAdapter对接口的路由请求进行处理
SimpleHandlerAdapter通过适配器获取并执行全部过滤器。

HandlerResultHandler
在这里插入图片描述

创建DispatcherHandler实例化了4个HandlerResultHandler

HandlerResultHandler请求处理作用
ResponseBodyResultHandler处理使用@ResponseBody修饰的http请求的处理器
ResponseEntityResultHandler处理的http请求的处理器
ServerResponseResultHandler用于处理来自网关路由的响应结果的处理器
ViewResolutionResultHandler它负责处理解析视图的结果。在Spring Cloud Gateway中,视图通常指的是我们想要转发请求到的目的地。

请求处理阶段

网关入口是ReactorHttpHandlerAdapter#apply方法,当HTTP请求进入该方法后会去获取请求的request和response,构建当次请求的上下文供后续filter使用。

apply方法
public class ReactorHttpHandlerAdapter implements BiFunction<HttpServerRequest, HttpServerResponse, Mono<Void>>{@Overridepublic Mono<Void> apply(HttpServerRequest reactorRequest, HttpServerResponse reactorResponse) {NettyDataBufferFactory bufferFactory = new NettyDataBufferFactory(reactorResponse.alloc());try {//获取请求的Request,构建ReactorServerHttpRequestReactorServerHttpRequest request = new ReactorServerHttpRequest(reactorRequest, bufferFactory);//构建ServerHttpResponseServerHttpResponse response = new ReactorServerHttpResponse(reactorResponse, bufferFactory);//Heade 请求 构建Header类型的responseif (request.getMethod() == HttpMethod.HEAD) {response = new HttpHeadResponseDecorator(response);}//交给HttpWebHandlerAdapter构建上下文ServerWebExchangereturn this.httpHandler.handle(request, response)//失败.doOnError(ex -> logger.trace(request.getLogPrefix() + "Failed to complete: " + ex.getMessage()))//成功.doOnSuccess(aVoid -> logger.trace(request.getLogPrefix() + "Handling completed"));}catch (URISyntaxException ex) {//异常处理并返回}}//省略部分代码
}

this.httpHandler.handle 最终是调用org.springframework.web.server.adapter.HttpWebHandlerAdapter#handle进行处理。

httpHandler#handle方法
	@Overridepublic Mono<Void> handle(ServerHttpRequest request, ServerHttpResponse response) {//forwardedHeaderTransformer不为空,需要删除一些不需要往下传递的Headersif (this.forwardedHeaderTransformer != null) {request = this.forwardedHeaderTransformer.apply(request);}//构建ServerWebExchange网关的上下文对象 默认实例:DefaultServerWebExchangeServerWebExchange exchange = createExchange(request, response);//日志打印LogFormatUtils.traceDebug(logger, traceOn ->exchange.getLogPrefix() + formatRequest(exchange.getRequest()) +(traceOn ? ", headers=" + formatHeaders(exchange.getRequest().getHeaders()) : ""));//getDelegate获取到ExceptionHandlingWebHandler //去处理ServerWebExchange网关的上下文对象return getDelegate().handle(exchange).doOnSuccess(aVoid -> logResponse(exchange)).onErrorResume(ex -> handleUnresolvedError(exchange, ex)).then(Mono.defer(response::setComplete));}

构建完request和response后,交给HttpWebHandlerAdapter构建上下文ServerWebExchange(实现类:DefaultServerWebExchange)。

并交由WebHandler#handle处理网关上下文。

WebHandler#handle方法

这里有一个区分HttpHanler接口是WebFulx响应式编程的接口规范。webHandler是Servlet的接口规范。getDelegate方法获取到的WebHandler是一个装饰类如图:
在这里插入图片描述
链路如下:

ExceptionHandlingWebHandler

—> FilteringWebHandler

​ —> DispatcherHandler

  • ExceptionHandlingWebHandler 对WebHandler进行异常处理的包装

  • FilteringWebHandler 注意该类为org.springframework.web.server.handler.FilteringWebHandler而非org.springframework.cloud.gateway.handler.FilteringWebHandler

前者是web服务提供的filter处理器,后者是gateway提供的网关filter处理器。

  • DispatcherHandler 我们熟悉的网关请求处理入口。

ExceptionHandlingWebHandler#hander

@Override
public Mono<Void> handle(ServerWebExchange exchange) {Mono<Void> completion;//交给其父类去处理 WebHandlerDecorator的handle方法try {completion = super.handle(exchange);}catch (Throwable ex) {completion = Mono.error(ex);}//使用该类的异常处理类进行异常处理(ExceptionHandlingWebHandler主要作用)for (WebExceptionHandler handler : this.exceptionHandlers) {completion = completion.onErrorResume(ex -> handler.handle(exchange, ex));}return completion;
}

将真实的请求交给委托父类处理,只对请求完成后的异常情况进行处理。

WebHandlerDecorator的handle

该方法调用的org.springframework.web.server.handler.FilteringWebHandler的handle

public Mono<Void> handle(ServerWebExchange exchange) {return this.chain.filter(exchange);
}

DefaultWebFilterChain#filter
在这里插入图片描述
//该chain包含过滤器列表和一个Handler

  • allFilters 所有需要执行的过滤器组件(webFlux的过滤器)
  • DispatchHanlder 上文说到的网关请求的转发的入口。
//chain为DefaultWebFilterChain
public Mono<Void> filter(ServerWebExchange exchange) {//执行所有的过滤器,过滤器执行完毕后将请求交给DispatchHanlderHandler进行处理return Mono.defer(() ->this.currentFilter != null && this.chain != null ?invokeFilter(this.currentFilter, this.chain, exchange) :this.handler.handle(exchange));
}
DispatchHanlder#handle方法
@Override
public Mono<Void> handle(ServerWebExchange exchange) {//如果获取不到网关请求映射则返回未发现异常if (this.handlerMappings == null) {return createNotFoundError();}//响应式处理 三部完成return Flux.fromIterable(this.handlerMappings)//第一步 根据网关上下文获取对应的请求映射HandlerMapping.concatMap(mapping -> mapping.getHandler(exchange)).next().switchIfEmpty(createNotFoundError())//第二步 执行请求处理.flatMap(handler -> invokeHandler(exchange, handler))//第三步 处理返回结果.flatMap(result -> handleResult(exchange, result));
}

mapping.getHandler

@Override
public Mono<Object> getHandler(ServerWebExchange exchange) {//getHandlerInternal 根据路由规则获取对应的Handlerreturn getHandlerInternal(exchange).map(handler -> {if (logger.isDebugEnabled()) {logger.debug(exchange.getLogPrefix() + "Mapped to " + handler);}//跨域请求的处理ServerHttpRequest request = exchange.getRequest();if (hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) {CorsConfiguration config = (this.corsConfigurationSource != null ? this.corsConfigurationSource.getCorsConfiguration(exchange) : null);CorsConfiguration handlerConfig = getCorsConfiguration(handler, exchange);config = (config != null ? config.combine(handlerConfig) : handlerConfig);if (!this.corsProcessor.process(config, exchange) || CorsUtils.isPreFlightRequest(request)) {return REQUEST_HANDLED_HANDLER;}}return handler;});
}

该方法主要做两件事

  1. 根据路由规则获取对应的Handler
  2. 如果请求为跨域,则为该Handler添加跨域相关配置。

在上面我们分析创建DispatcherHandler实例化了6个HandlerMapping。其中跟网关有关的映射为RoutePredicateHandlerMapping

第一步 getHandler获取请求映射

RoutePredicateHandlerMapping#getHandlerInternal实现类获取路由信息

protected Mono<?> getHandlerInternal(ServerWebExchange exchange) {if (this.managementPortType == RoutePredicateHandlerMapping.ManagementPortType.DIFFERENT && this.managementPort != null && exchange.getRequest().getURI().getPort() == this.managementPort) {return Mono.empty();} else {exchange.getAttributes().put(ServerWebExchangeUtils.GATEWAY_HANDLER_MAPPER_ATTR, this.getSimpleName());//根据路由上下文 查询对应的Route信息return this.lookupRoute(exchange).flatMap((r) -> {exchange.getAttributes().remove(ServerWebExchangeUtils.GATEWAY_PREDICATE_ROUTE_ATTR);if (this.logger.isDebugEnabled()) {this.logger.debug("Mapping [" + this.getExchangeDesc(exchange) + "] to " + r);}exchange.getAttributes().put(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR, r);return Mono.just(this.webHandler);}).switchIfEmpty(Mono.empty().then(Mono.fromRunnable(() -> {exchange.getAttributes().remove(ServerWebExchangeUtils.GATEWAY_PREDICATE_ROUTE_ATTR);if (this.logger.isTraceEnabled()) {this.logger.trace("No RouteDefinition found for [" + this.getExchangeDesc(exchange) + "]");}})));}
}

上面代码很多其实我们只需要关注lookupRoute 故名思义:根据路由上下文获得对应的路由(Route)信息。继续看lookupRoute。

lookupRoute方法

protected Mono<Route> lookupRoute(ServerWebExchange exchange) {//变量所有的路由信息(服务启动的时候会加载我们所有配置的路由信息)return this.routeLocator.getRoutes().concatMap((route) -> {return Mono.just(route).filterWhen((r) -> {exchange.getAttributes().put(ServerWebExchangeUtils.GATEWAY_PREDICATE_ROUTE_ATTR, r.getId());//根据断言语句判断是否是符合条件的路由并返回return (Publisher)r.getPredicate().apply(exchange);}).doOnError((e) -> {this.logger.error("Error applying predicate for route: " + route.getId(), e);}).onErrorResume((e) -> {return Mono.empty();});}).next().map((route) -> {if (this.logger.isDebugEnabled()) {this.logger.debug("Route matched: " + route.getId());}//校验路由 目前为空实现this.validateRoute(route, exchange);return route;});
}

根据路由条件获取对应的路由信息,其中所有配置的路由信息是存放在this.routeLocator(RouteLocator)中。RouteLocator在自动化装配类GatewayAutoConfiguration中被初始化。RouteLocator有如下三种实现。

  • RouteDefinitionRouteLocator 基于路由定义的定位器。
  • CachingRouteLocator 基于缓存的路由定位器。
  • CompositeRouteLocator 基于组合方式的路由定位器。
第二步 invokeHandler 请求适配

​ 上述getHandler 最终返回的是org.springframework.cloud.gateway.handler.FilteringWebHandler实例。接着通过适配器HandlerAdapters去处理FilteringWebHandler实例。

DispatcherHandler#invokeHandler

private Mono<HandlerResult> invokeHandler(ServerWebExchange exchange, Object handler) {if (this.handlerAdapters != null) {//获取DispatcherHandler中的符合条件的HandlerAdapter进行请求适配//support 为判断方法 因为网关默认是WebHandler所有跟网关有关的适配器为SimpleHandlerAdapterfor (HandlerAdapter handlerAdapter : this.handlerAdapters) {if (handlerAdapter.supports(handler)) {return handlerAdapter.handle(exchange, handler);}}}return Mono.error(new IllegalStateException("No HandlerAdapter: " + handler));
}

同理,在上面我们分析创建DispatcherHandler实例化了3个HandlerAdapters 因为网关默认是WebHandler所有跟网关有关的适配器为SimpleHandlerAdapter

SimpleHandlerAdapter#handle

@Override
public Mono<HandlerResult> handle(ServerWebExchange exchange, Object handler) {WebHandler webHandler = (WebHandler) handler;Mono<Void> mono = webHandler.handle(exchange);return mono.then(Mono.empty());
}

直接将handler转换为WebHandler调用其handle,最终就是调用FilteringWebHandler#handle方法执行请求

FilteringWebHandler#handle

public Mono<Void> handle(ServerWebExchange exchange) {//从ServerWebExchange网关上下文中获取匹配到的路由信息,在上面匹配成功后会将路由信息存放在ServerWebExchange网关上下文属性中Route route = (Route)exchange.getRequiredAttribute(ServerWebExchangeUtils.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);}//创建DefaultGatewayFilterChain 执行过滤器链return (new DefaultGatewayFilterChain(combined)).filter(exchange);
}

上面就是适配器的主要流程,主要分五步

  1. 从ServerWebExchange网关上下文中获取匹配到的路由信息
  2. 获取路由信息中配置的过滤器局部过滤器以及全局过滤器,合并到一起并排序
  3. 创建责任链DefaultGatewayFilterChain执行所有的过滤器

所有按照优先级排序后的过滤器如下:
在这里插入图片描述

比较重要的过滤器

过滤器作用
RouteToRequestUrlFilter将域名和端口转换成调用的服务,并且判断了是否需要进行负载均衡
LoadBalancerClientFilter根据 lb://user-service 从注册中心获取到一个服务实例的ip和端口
NettyRoutingFilter发送真实的业务请求
WebsocketRoutingFilter可以处理"ws://","wss://"等 websocket协议。

其中有一个Filter即为请求转发到具体的服务节点的过滤器。从而执行真正的业务请求。笔者经过实验得到为NettyRoutingFilter来将请求调用真实业务请求。

public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {//获取真实的业务请求urlURI requestUrl = (URI)exchange.getRequiredAttribute(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR);String scheme = requestUrl.getScheme();//首次请求 且为Http或者Https则构建参数执行请求if (!ServerWebExchangeUtils.isAlreadyRouted(exchange) && ("http".equals(scheme) || "https".equals(scheme))) {       //标记完成(保证一次请求执行一次)ServerWebExchangeUtils.setAlreadyRouted(exchange);//获取请求对象ServerHttpRequest request = exchange.getRequest();//methodHttpMethod method = HttpMethod.valueOf(request.getMethodValue());//urlString url = requestUrl.toASCIIString();//请求头headerHttpHeaders filtered = HttpHeadersFilter.filterRequest(this.getHeadersFilters(), exchange);DefaultHttpHeaders httpHeaders = new DefaultHttpHeaders();filtered.forEach(httpHeaders::set);boolean preserveHost = (Boolean)exchange.getAttributeOrDefault(ServerWebExchangeUtils.PRESERVE_HOST_HEADER_ATTRIBUTE, false);Route route = (Route)exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR);//webFlux执行请求Flux<HttpClientResponse> responseFlux = ((HttpClient.RequestSender)this.getHttpClient(route, exchange).headers((headers) -> {headers.add(httpHeaders);headers.remove("Host");if (preserveHost) {String host = request.getHeaders().getFirst("Host");headers.add("Host", host);}}).request(method).uri(url)).send((req, nettyOutbound) -> {if (log.isTraceEnabled()) {nettyOutbound.withConnection((connection) -> {log.trace("outbound route: " + connection.channel().id().asShortText() + ", inbound: " + exchange.getLogPrefix());});}return nettyOutbound.send(request.getBody().map(this::getByteBuf));}).responseConnection((res, connection) -> {//构建响应信息exchange.getAttributes().put(ServerWebExchangeUtils.CLIENT_RESPONSE_ATTR, res);exchange.getAttributes().put(ServerWebExchangeUtils.CLIENT_RESPONSE_CONN_ATTR, connection);ServerHttpResponse response = exchange.getResponse();HttpHeaders headers = new HttpHeaders();res.responseHeaders().forEach((entry) -> {headers.add((String)entry.getKey(), (String)entry.getValue());});String contentTypeValue = headers.getFirst("Content-Type");if (StringUtils.hasLength(contentTypeValue)) {exchange.getAttributes().put("original_response_content_type", contentTypeValue);}this.setResponseStatus(res, response);HttpHeaders filteredResponseHeaders = HttpHeadersFilter.filter(this.getHeadersFilters(), headers, exchange, Type.RESPONSE);if (!filteredResponseHeaders.containsKey("Transfer-Encoding") && filteredResponseHeaders.containsKey("Content-Length")) {response.getHeaders().remove("Transfer-Encoding");}exchange.getAttributes().put(ServerWebExchangeUtils.CLIENT_RESPONSE_HEADER_NAMES, filteredResponseHeaders.keySet());response.getHeaders().putAll(filteredResponseHeaders);return Mono.just(res);});Duration responseTimeout = this.getResponseTimeout(route);if (responseTimeout != null) {responseFlux = responseFlux.timeout(responseTimeout, Mono.error(new TimeoutException("Response took longer than timeout: " + responseTimeout))).onErrorMap(TimeoutException.class, (th) -> {return new ResponseStatusException(HttpStatus.GATEWAY_TIMEOUT, th.getMessage(), th);});}return responseFlux.then(chain.filter(exchange));} else {return chain.filter(exchange);}
}
第三步 handleResult请求处理

其实到上面的过滤器链执行完毕后整个业务请求也执行完毕,如果需要在对业务请求进行相关的特殊处理则需要就到了最后一步进行请求处理。

笔者参考了公司的项目以及网上的相关实例,都没有找到使用HandlerResultHandler进行处理的场景,即使有想过返回值的处理情况,大部分的解决方案是使用自定义过滤器,不会使用handleResult

鉴于时机场景没有使用,这里只对该流程进行简单分析,在上面我们分析创建DispatcherHandler实例化了4个HandlerResultHandler。

//获取符合了条件的HandlerResultHandler
private HandlerResultHandler getResultHandler(HandlerResult handlerResult) {if (this.resultHandlers != null) {for (HandlerResultHandler resultHandler : this.resultHandlers) {if (resultHandler.supports(handlerResult)) {return resultHandler;}}}throw new IllegalStateException("No HandlerResultHandler for " + handlerResult.getReturnValue());
}
//调用HandlerResultHandler对业务逻辑进行处理。
Mono<Void> handleResult(ServerWebExchange exchange, HandlerResult result);
总结
  • Gateway Client向 Spring Cloud Gateway 发送请求。

  • 请求首先会被ReactorHttpHandlerAdapter接收,构造Resquest和Response。

  • 然后会被HttpWebHandlerAdapter 进行提取组装成网关上下文ServerWebExchange。

  • 然后网关的上下文会传递到DispatcherHandler ,它负责将请求分发给 RoutePredicateHandlerMapping。

  • RoutePredicateHandlerMapping负责路由查找,并根据路由断言判断路由是否可用。

  • 如果过断言成功,由FilteringWebHandler 创建过滤器链并调用。

  • 通过特定于请求的 Fliter 链运行请求,Filter 被虚线分隔的原因是Filter可以在发送代理请求之前(pre)和之后(post)运行逻辑。

  • 执行所有pre过滤器逻辑。然后进行代理请求。发出代理请求后,将运行“post”过滤器逻辑。

  • 处理完毕之后将 Response 返回到 Gateway 客户端。
    在这里插入图片描述


http://www.ppmy.cn/embedded/31563.html

相关文章

【数据库原理及应用】期末复习汇总高校期末真题试卷

试卷 一、填空题 1.________是位于用户与操作系统之间的一层数据管理软件。 2.数据库系统的三级模式结构是指________、________、________。 3.数据库系统的三种数据模型是________ 、________、________。 4.若关系中的某一属性组的值能唯一地标识一个元组&#xff0c;则…

【算法】深度优先搜索岛屿数量

1、题目描述 有一个由0和1组成的二维矩阵&#xff0c;其中1代表陆地&#xff0c;0代表水&#xff0c;岛屿由水平或垂直方向上相邻的陆地连接形成。 假设矩阵的四周均被水包围&#xff0c;请计算岛屿的数量。 输入&#xff1a;matrix [[1,1,0,0],[0,0,1,0],[0,0,0,0],[0,0,1,1],…

WAAP动态安全解决方案

随着企业数字化进程不断加速&#xff0c;应用安全面临多重威胁&#xff0c;新型攻击方式层出不穷&#xff0c;常见的攻击形式包括Web应用攻击、DDoS攻击、API攻击、恶意爬虫攻击等。企业正面临严峻的安全防护挑战&#xff0c;需寻找一个可靠、全面的安全解决方案。在此情况下&a…

Apache SSI远程命令执行漏洞

什么是SSI Apache SSI&#xff08;Server Side Include)&#xff0c;通常称为"服务器端嵌入"或者叫"服务器端包含"&#xff0c;是一种类似于ASP的基于服务器的网页制作技术。默认扩展名是 .stm、.shtm 和 .shtml。 从技术层面来讲&#xff0c;SSI是一种在静…

【C++】深入剖析C++11 initializer_list 新的类功能 可变模板参数

目录 一、std::initializer_list 1、std::initializer_list是什么类型 2、std::initializer_list 的应用场景 ①给自定义容器赋值 ② 传递同类型的数据集合 二、新的类功能 1、默认成员函数 2、关键字default 3、关键字delete 三、可变参数模板 一、std::initialize…

题目:吃奶酪

问题描述&#xff1a; 解题思路&#xff1a; 枚举每种吃奶酪顺序&#xff0c;并计算其距离&#xff0c;选择最小的距离即答案。v数组&#xff1a;记录顺序。 注意点&#xff1a;1. 每次用于min的s需要重置为0。 2. 实数包括小数&#xff0c;所以结构体内x,y为double类型。 3. 第…

【QT】初始QT

目录 一.背景1.GUI开发的各种技术方案2.什么是框架3.QT支持的系统4.QT的版本5.QT的优点6.QT的应用常见 二.环境搭建1.认识QTSDK中的重要工具2.使用QT Creator创建项目3.项目解释(1)main.cpp(2)widget.h(3)widget.cpp(4)widget.ui(5)Empty.pro(6)临时文件 三.初始QT1.Hello Worl…

[初阶数据结构】时间复杂度与空间复杂度

前言 &#x1f4da;作者简介&#xff1a;爱编程的小马&#xff0c;正在学习C/C&#xff0c;Linux及MySQL。 &#x1f4da;本文收录于初阶数据结构系列&#xff0c;本专栏主要是针对时间、空间复杂度&#xff0c;顺序表和链表、栈和队列、二叉树以及各类排序算法&#xff0c;持续…