Spring Cloud Gateway-自定义异常处理
2021-05-28 11:00
标签:erro 架构 ref webapp boot 添加 节点 order owa 我们平时在用 先画一个假想但是贴近实际架构图,定位一下网关的作用: 网关在整个架构中的作用是: 假设网关服务总是正常的前提下: 对于第1点来说,假设后端应用不能平滑无损上线,会有一定的几率出现网关路由请求到一些后端的“僵尸节点(请求路由过去的时候,应用更好在重启或者刚好停止)”,这个时候会路由会失败抛出异常,一般情况是Connection Refuse。 对于第2点来说,假设后端应用没有正确处理异常,那么应该会把异常信息经过网关转发回到服务端应用,这种情况理论上不会出现异常。 其实还有第3点隐藏的问题,网关如果不单单承担路由的功能,还包含了鉴权、限流等功能,如果这些功能开发的时候对异常捕获没有做完善的处理甚至是逻辑本身存在BUG,有可能导致异常没有被正常捕获处理,走了默认的异常处理器 在 我们可以先看默认的异常处理器的配置类 注意到两个Bean实例 我们需要分析一下 确定三点: 自定义的 配置类 很简单,这里把异常的HTTP响应状态码统一为 重写这个方法:Map 参考(https://www.jianshu.com/p/b64a6154d742) 或者:重写springboot的org.springframework.boot.web.reactive.error.DefaultErrorAttributes类的Map 测试场景一:只启动网关,下游服务不启动的情况下直接调用下游服务: 测试场景二:下游服务正常启动和调用,网关自身抛出异常。 在网关应用自定义一个全局过滤器并且故意抛出异常: 响应结果和定制的逻辑一致,并且后台的日志也打印了对应的异常堆栈。 笔者一直认为,做异常分类和按照分类处理是工程里面十分重要的一环。笔者在所在公司负责的系统中,坚持实现异常分类捕获,主要是需要区分可以重试补偿以及无法重试需要及时预警的异常,这样子才能针对可恢复异常定制自愈逻辑,对不能恢复的异常及时预警和人为介入。所以, 转自: https://www.cnblogs.com/throwable/p/10848879.html https://www.jianshu.com/p/b64a6154d742 Spring Cloud Gateway-自定义异常处理 标签:erro 架构 ref webapp boot 添加 节点 order owa 原文地址:https://www.cnblogs.com/duanxz/p/14786337.html一、前提
SpringMVC
的时候,只要是经过DispatcherServlet
处理的请求,可以通过@ControllerAdvice
和@ExceptionHandler
自定义不同类型异常的处理逻辑,具体可以参考ResponseEntityExceptionHandler
和DefaultHandlerExceptionResolver
,底层原理很简单,就是发生异常的时候搜索容器中已经存在的异常处理器并且匹配对应的异常类型,匹配成功之后使用该指定的异常处理器返回结果进行Response
的渲染,如果找不到默认的异常处理器则用默认的进行兜底(个人认为,Spring在很多功能设计的时候都有这种“有则使用自定义,无则使用默认提供”这种思想十分优雅)。SpringMVC
中提供的自定义异常体系在Spring-WebFlux
中并不适用,其实原因很简单,两者底层的运行容器并不相同。WebExceptionHandler
是Spring-WebFlux
的异常处理器顶层接口,因此追溯到子类可以追踪到DefaultErrorWebExceptionHandler
是Spring Cloud Gateway
的全局异常处理器,配置类是ErrorWebFluxAutoConfiguration
。二、为什么要自定义异常处理
DefaultErrorWebExceptionHandler
,默认的异常处理器的处理逻辑可能并不符合我们预期的结果。三、如何自定义异常处理
3.1、SpringCloudGateway异常处理类间关系
org.springframework.boot.autoconfigure.web.reactive.error
包下有三个类用于处理异常。DefaultErrorWebExceptionHandler
然后将我们处理异常的逻辑替换原有的逻辑。然后通过配置类,将自己写的类替换原有的类即可。3.2、自定义异常处理实现
Map
已经被标记为过时,使用Map
取代,所以我们需要重写这个方法就可以了。3.2.1、(springboot2.3之前版本)
ErrorWebFluxAutoConfiguration
:@Configuration
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
@ConditionalOnClass(WebFluxConfigurer.class)
@AutoConfigureBefore(WebFluxAutoConfiguration.class)
@EnableConfigurationProperties({ ServerProperties.class, ResourceProperties.class })
public class ErrorWebFluxAutoConfiguration {
private final ServerProperties serverProperties;
private final ApplicationContext applicationContext;
private final ResourceProperties resourceProperties;
private final List
ErrorWebExceptionHandler
和DefaultErrorAttributes
都使用了@ConditionalOnMissingBean
注解,也就是我们可以通过自定义实现去覆盖它们。先自定义一个CustomErrorWebFluxAutoConfiguration
(除了ErrorWebExceptionHandler
的自定义实现,其他直接拷贝ErrorWebFluxAutoConfiguration
):@Configuration
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
@ConditionalOnClass(WebFluxConfigurer.class)
@AutoConfigureBefore(WebFluxAutoConfiguration.class)
@EnableConfigurationProperties({ServerProperties.class, ResourceProperties.class})
public class CustomErrorWebFluxAutoConfiguration {
private final ServerProperties serverProperties;
private final ApplicationContext applicationContext;
private final ResourceProperties resourceProperties;
private final List
ErrorWebExceptionHandler
的实现,可以直接参考DefaultErrorWebExceptionHandler
,甚至直接继承DefaultErrorWebExceptionHandler
,覆盖对应的方法即可。这里直接把异常信息封装成下面格式的Response
返回,最后需要渲染成JSON格式:{
"code": 200,
"message": "描述信息",
"path" : "请求路径",
"method": "请求方法"
}
DefaultErrorWebExceptionHandler
中的一些源码:// 封装异常属性
protected Map
DefaultErrorWebExceptionHandler#getErrorAttributes()
,并且结果是一个Map
实例转换成的字节序列。RouterFunction
实现只支持HTML格式返回,我们需要修改为JSON格式返回(或者说支持所有格式返回)。DefaultErrorWebExceptionHandler#getHttpStatus()
是响应状态码的封装,原来的逻辑是基于异常属性getErrorAttributes()
的status属性进行解析的。JsonErrorWebExceptionHandler
如下:public class JsonErrorWebExceptionHandler extends DefaultErrorWebExceptionHandler {
public JsonErrorWebExceptionHandler(ErrorAttributes errorAttributes,
ResourceProperties resourceProperties,
ErrorProperties errorProperties,
ApplicationContext applicationContext) {
super(errorAttributes, resourceProperties, errorProperties, applicationContext);
}
@Override
protected Map
CustomErrorWebFluxAutoConfiguration
添加JsonErrorWebExceptionHandler
:@Bean
@ConditionalOnMissingBean(value = ErrorWebExceptionHandler.class, search = SearchStrategy.CURRENT)
@Order(-1)
public ErrorWebExceptionHandler errorWebExceptionHandler(ErrorAttributes errorAttributes) {
JsonErrorWebExceptionHandler exceptionHandler = new JsonErrorWebExceptionHandler(
errorAttributes,
resourceProperties,
this.serverProperties.getError(),
applicationContext);
exceptionHandler.setViewResolvers(this.viewResolvers);
exceptionHandler.setMessageWriters(this.serverCodecConfigurer.getWriters());
exceptionHandler.setMessageReaders(this.serverCodecConfigurer.getReaders());
return exceptionHandler;
}
HttpStatus.INTERNAL_SERVER_ERROR(500)
,改造的东西并不多,只要了解原来异常处理的上下文逻辑即可。3.2.2、(springboot2.3之后版本)
public class GatewayErrorAttributes extends DefaultErrorAttributes {
private static final Logger log = LoggerFactory.getLogger(GatewayExceptionHandler.class);
@Override
public Map
四、测试
curl http://localhost:9090/order/host
// 响应结果
{"path":"/order/host","code":500,"message":"Connection refused: no further information: localhost/127.0.0.1:9091","method":"GET"}
@Component
public class ErrorGlobalFilter implements GlobalFilter {
@Override
public Mono
curl http://localhost:9090/order/host
// 响应结果
{"path":"/order/host","code":500,"message":"/ by zero","method":"GET"}
五、小结
Spring Cloud Gateway
这个技术栈也必须调研其自定义异常的处理逻辑。
文章标题:Spring Cloud Gateway-自定义异常处理
文章链接:http://soscw.com/index.php/essay/88634.html