摘要:在这里,会将上下文中载入的拼接成,然后调用其方法的,它是的处理请求业务的起点。添加相关依赖之后,会有这个。路由权重相关配置功能相关实现类,这个我们这里不关心。
我们继续分析上一节提到的 WebHandler
,经过将请求封装成 ServerWebExchange 的 HttpWebHandlerAdapter 之后,请求会经过 ExceptionHandlingWebHandler
之前有网友私信问过笔者,如何给 Spring Cloud Gateway 加全局异常处理器,其实和给基于 Spring-Flux 的异步 Web 服务加是一样的,都是通过实现并注册一个 WebExceptionHandler
Bean:
public interface WebExceptionHandler { Mono handle(ServerWebExchange exchange, Throwable ex);}
这些 Bean,就是在 ExceptionHandlingWebHandler 被加入到整个请求处理链路中的:
ExceptionHandlingWebHandler.java
@Overridepublic Mono handle(ServerWebExchange exchange) { Mono completion; try { //这里其实就是组装后面的链路,即调用后面的 FilteringWebHandler 的 handle completion = super.handle(exchange); } catch (Throwable ex) { completion = Mono.error(ex); } for (WebExceptionHandler handler : this.exceptionHandlers) { completion = completion.onErrorResume(ex -> handler.handle(exchange, ex)); } return completion;}
从源码可以看出,这里将每个 WebExceptionHandler
作为 Mono 的异常处理 onErrorResume
加入了链路。onErrorResume
的意思是如果链路前面发生异常,则在这里捕获住异常同时调用 handler.handle(exchange, ex)
进行处理,如果使用阻塞代码理解,就相当于:
try { //前面的链路} catch(Throwable ex) { return handler.handle(exchange, ex)}
这里我们看到有多个 WebExceptionHandler
,都会在链路后面追加 onErrorResume
,其实就相当于:
completion.onErrorResume(ex -> webExceptionHandler1.handle(exchange, ex)).onErrorResume(ex -> webExceptionHandler2.handle(exchange, ex)).onErrorResume(ex -> webExceptionHandler3.handle(exchange, ex))...
转换成阻塞代码理解,其实就是:
try { completion} catch(Throwable e1) { try { return webExceptionHandler1.handle(exchange, e1) } catch(Throwable e2) { try { return webExceptionHandler2.handle(exchange, ex) } catch(Throwable e2) { return webExceptionHandler3.handle(exchange, ex) //如果还有就继续叠加 } }}
当 WebExceptionHandler 可以处理这个异常的时候,他的 handle
方法会返回一个真正的响应,否则会返回异常,例如:
public class WebExceptionHandler1 implements WebExceptionHandler { @Override public Mono handle(ServerWebExchange exchange, Throwable ex) { //如果是 ResponseStatusException 则使用异常里面的响应码和 HTTP 头填充响应的响应码和 HTTP 头 if (ex instanceof ResponseStatusException) { ServerHttpResponse response = exchange.getResponse(); ResponseStatusException responseStatusException = (ResponseStatusException) ex; response.setRawStatusCode(responseStatusException.getRawStatusCode()); responseStatusException.getResponseHeaders() .forEach((name, values) -> values.forEach(value -> response.getHeaders().add(name, value))); //返回响应完成 return response.setComplete(); } //抛出异常,继续链路异常处理 return Mono.error(ex); }}
转换成同步代码去理解其实就是:
if (ex instanceof ResponseStatusException) { ServerHttpResponse response = exchange.getResponse(); ResponseStatusException responseStatusException = (ResponseStatusException) ex; response.setRawStatusCode(responseStatusException.getRawStatusCode()); responseStatusException.getResponseHeaders() .forEach((name, values) -> values.forEach(value -> response.getHeaders().add(name, value))); //返回响应完成 return response.setComplete();}//抛出异常,继续链路异常处理throw ex;
如果大家想封装自己统一的错误响应,可以通过实现这个接口进行实现。
接下来进入 FilteringWebHandler,注意是 org.springframework.web.server.handler.FilteringWebHandler
而不是 Spring Cloud Gateway 的 org.springframework.cloud.gateway.handler.FilteringWebHandler
。在这里,会将上下文中载入的 WebFilter 拼接成 DefaultWebFilterChain
,然后调用其 filter 方法:
private final DefaultWebFilterChain chain;public FilteringWebHandler(WebHandler handler, List filters) { super(handler); this.chain = new DefaultWebFilterChain(handler, filters);}@Overridepublic Mono handle(ServerWebExchange exchange) { return this.chain.filter(exchange);}
Spring Cloud Gateway 的 FilteringWebHandler, 它是 Spring Cloud Gateway 的处理请求业务的起点。在这里我们即将进入整个 Spring Cloud Gateway 的 Filter 链路,包括每个路径自己的 GatewayFilter
以及全局的 GlobalGatewayFilter
,都是在这里开始被处理组装成完整调用链路的。我们后面还会提到
由于我们的项目依赖中包含了 Spring Cloud Sleuth 以及 Prometheus 的依赖,所以我们这里的 WebFilter 会包括三个:
org.springframework.boot.actuate.metrics.web.reactive.server.MetricsWebFilter
:添加 Prometheus 相关依赖之后,会有这个 MetricsWebFilter,用于记录请求处理耗时,采集相关指标。org.springframework.cloud.sleuth.instrument.web.TraceWebFilter
:添加 Spring Cloud Sleuth 相关依赖之后,会有这个 TraceWebFilter。org.springframework.cloud.gateway.handler.predicate.WeightCalculatorWebFilter
:Spring Cloud Gateway 路由权重相关配置功能相关实现类,这个我们这里不关心。其具体流程,我们在下一节中继续详细分析。
微信搜索“我的编程喵”关注公众号,每日一刷,轻松提升技术,斩获各种offer:
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/125367.html
摘要:在这里,会将上下文中载入的拼接成,然后调用其方法的,它是的处理请求业务的起点。添加相关依赖之后,会有这个。路由权重相关配置功能相关实现类,这个我们这里不关心。 本系列代码地址:https://github.com/JoJoTec/spring-cloud-parent我们继续分析上一节提到的 WebHandle...
摘要:将请求封装成将请求封装成的接口定义是但是最外层传进来的参数是和,需要将他们封装成,这个工作就是在中做的。其实主要任务就是将各种参数封装成除了和本次请求相关的和,还有会话管理器,编码解码器配置,国际化配置还有用于扩展。本系列代码地址:https://github.com/JoJoTec/spring-cloud-parent接下来,将进入我们升级之路的又一大模块,即网关模块。网关模块我们废弃了...
摘要:添加相关依赖之后,会有这个。接着,根据的源码分析,会继续链路,到达下一个,即。在中,我们会计算出路由并发送请求到符合条件的。这个是的,会读取配置并生成路由。本系列代码地址:https://github.com/JoJoTec/spring-cloud-parent我们继续分析上一节提到的 WebHandler。加入 Spring Cloud Sleuth 以及 Prometheus 相关依赖...
摘要:升级之路版基本流程讲解抽象类本系列代码地址我们继续分析上一节提到的。添加相关依赖之后,会有这个。路由权重相关配置功能相关实现类,这个我们这里不关心。这个是的,会读取配置并生成路由。 本系列代码地址:https://github.com/JoJoTec/spring-cloud-parent我们继续分析上一节提到的 ...
摘要:对于异步的请求,使用的是异步客户端即。要实现的配置设计以及使用举例要实现的配置设计以及使用举例首先,我们要实现的,其包含三个重试重试的要在负载均衡之前,因为重试的时候,我们会从负载均衡器获取另一个实例进行重试,而不是在同一个实例上重试多次。 本系列代码地址:https://github.com/JoJoTec/spring-cloud-parent 为何需要封装异步 HT...
阅读 3666·2023-01-11 11:02
阅读 4206·2023-01-11 11:02
阅读 3004·2023-01-11 11:02
阅读 5145·2023-01-11 11:02
阅读 4699·2023-01-11 11:02
阅读 5483·2023-01-11 11:02
阅读 5234·2023-01-11 11:02
阅读 3858·2023-01-11 11:02