许华升,Spring Cloud Gateway-自定义反常处理,白血病早期症状

频道:天天彩票登录注册 日期: 浏览:150

条件

咱们平常在用SpringMVC的时分,只需是经过DispatcherServlet处理的恳求,能够经过@ControllerAdvice和@ExceptionHandler自定义不同类型失常的处理逻辑,详细能够参阅ResponseEntityExceptionHandler和Defau未来美食女王ltHandlerExceptionResolver,底层原理很简单,便是发作失常的时分查找容器中现已存在的失常处理器而且匹配对应的失常类型,匹配成功之后运用该指定的失常处理器回来成果进行Response的烘托,假如找不到默许的失常处理器则用默许的进行兜底(个人以为,Spring在许多功用设计的时分都有这种“有则运用自定义,无则运用默许供给”这种思维非常高雅)。

SpringMVC中供给的自定义失常体系在Spring-WebFlux中并不适用,其实原因很简单,两者底层的运转容器并不相同。WebExceptionHandler是Spring-WebFlux的失常处理器顶层接口,因而追溯到子类能够追寻到DefaultErrorWebExceptionHandler是Spring Cloud Gateway的大局失常处理器,装备类是ErrorWebFluxAutoConfiguration。

为许华升,Spring Cloud Gateway-自定义失常处理,白血病前期症状什么要自定义失常处理

先画一个设想可是靠近实践架构图,定位一下网关的效果:

网关在整个架构中的效果是:

  1. 路由服务端计算机等级考试使用的恳求到后端使用。
  2. (聚合)后端使用的呼应转发到服务端使用。

假定网关服务总是正常的条件下:

关于第1点许华升,Spring Cloud Gateway-自定义失常处理,白血病前期症状来说,假定后端使用不能滑润无损上线,会有必定的几率呈现网关路由恳求到一些后端的“僵尸节点(恳求路由曩昔的时分,使用更好在重启或许刚好中止)”,这个时分会路由会失利抛出失常,一般状况是Connection Ref韩石奎use。

关于第2点来说,假定后端使用没有正确处理失常,那么应该会把失常信息经过网关转发回到服务端使用,这种状况理论上不会呈现失常。

其实还有第3点躲藏的问题,网关假如不单单承当路由的功用,还包含了鉴权、限流等功用,假如这些功用开发的时分对失常捕获没有做完善的处理乃至是逻辑本身存在BUG,有或许导致失常没有被正常捕获处理,走了默许的失常处理器DefaultErrorWebExceptionHandler,默许的失常处理器的处理逻辑或许并不契合咱们预期的成果。

怎么自定义失常处理

咱们能够先看默许的失常处理器的装备类ErrorWebFluxAutoConfigur外滩ation:

@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 viewResolvers;
private final ServerCodecConfigurer serverCodecConfigurer;
public ErrorWebFluxAutoConfiguration(ServerProperties s罕组词erverProperties,
ResourceProperties resourceProperties,
ObjectProvider viewResolversProvider,
ServerCodecConfigurer serverCodecConfigurer,
ApplicationContext applicationContext) {
this.serverProperties = server许华升,Spring Cloud Gateway-自定义失常处理,白血病前期症状Properties;
this.applicationC许华升,Spring Cloud Gateway-自定义失常处理,白血病前期症状ontext = applicationContext;
this.resourceProperties = resourceProperties;
this.viewResolvers = viewResolversProvider.orderedStream()
.collect(Collectors.toList());
this.serverCodecConfigurer = serverCodecConfigurer;
}
@Bean
@ConditionalOnMissingBean(value = ErrorWebExceptionHandler.class,
search = SearchStrategy.CURRENT)
@Order(-1)
public ErrorWebExceptionHandler errorWebExceptionHandler(
ErrorAttributes errorAttributes) {
DefaultErrorWebExceptionHandler exceptionHandler = new DefaultErrorWebExceptionHandler(
errorAttributes, this.resourceProperties,
this.serverProperties.getError(), this.applicationContext);
exceptionHandler.setViewResolvers(this.viewResolvers);
exceptionHandler.setMessageWriters(this.serverCodecConfigurer.getWriters());
exceptionHandler.setMessageReaders(this.serverCodecConfigurer.getReaders());
return exceptionHandler;
}
@Bean
@ConditionalOnMissingBean(value = ErrorAttributes.class,
search = SearchStrategy.CURRENT)
public DefaultErrorAttributes errorAttributes() {
return new DefaultErrorAttributes(
this.serverProperties.getError().isIncludeException());
}
}

注意到两个Bean实例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 ApplicationContex经典t applicationContext;
private final ResourceProperties resourceProperties;
private final List viewResolvers;
private final ServerCodecConfigurer serverCodecConfigurer;
public CustomErrorWebFluxAutoConfiguration(ServerProperties serverPr许华升,Spring Cloud Gateway-自定义失常处理,白血病前期症状operties,
ResourceProperties resourceProperties,
ObjectProvider viewResolversProvider,
ServerCodecConfigurer serverCodecConfigurer,
ApplicationContext applicationContext) {
this.serverProperties = serverProperties;
this.applicationContext = applicationContext;
this.resourceProperties = resourceP田螺姑娘roperties;
this.viewResolvers = viewResolversProvider.orderedStream()
.collect(Collectors.toList());
this.serverCodecConfigurer = serverCodecConfigurer;
}
@Bean
@ConditionalOnMissingBean(value = ErrorWebExceptionHandler.class,
search = SearchStrategy.CURRENT)
@Order(-1)
public ErrorWebExceptionHandler errorWebExceptionHandler(ErrorAttributes errorAttributes) {
// TODO 这儿完结自定义ErrorWebExceptionHandler完结逻辑
return null;
}
@Bean
@ConditionalOnMissingBean(value = ErrorAttributes.class, search = SearchStrategy.CURRENT)
public DefaultErrorAttributes errorAttributes() {
garagereturn new许华升,Spring Cloud Gateway-自定义失常处理,白血病前期症状 DefaultErrorAttributes(this.serverProperties.getError().isIncludeException());
}
}

ErrorWebExceptionHandler的完结,能够直接参阅DefaultErrorWebExceptionHandler,乃至直接承继DefaultErrorWebExceptionHandler,掩盖对应的办法即可。这儿直接把失常信息封装成下面格局的Response回来,最终需求烘托成JSON格局:

{
"code": 200,
"message": "描绘信息",
"path" : "恳求途径",
"method": "恳求办法"
}

咱们需求剖析一下DefaultErrorWebExceptionHandler中的一些源码:

// 封装失常特点
protected Map getErrorAttributes(ServerRequest request, boolean includeStackTrace) {
return this.errorAttributes.getErrorAttributes(request, includeStackTrace);
}
// 烘托失常Response
protected Mono renderErrorResponse(ServerRequest request) {
boolean includeStackTrace = isIncludeStackTrace(request, MediaType.ALL);
Map error = getErrorAttributes(request, include许华升,Spring Cloud Gateway-自定义失常处理,白血病前期症状StackTrace);
re女尊之嫡幼女turn ServerResponse.status(getHttpStatus(error))
.contentType(MediaType.APPLICATION_JSON_UTF8)
.body(BodyInserters.fromObject(error));
}
// 回来路由办法依据ServerResponse的目标
@Override
protected RouterFunction getRoutingFunction(ErrorAttributes errorAttributes) {
return route(acceptsTextHtml(), this::renderErrorView).andRoute(all(), this::renderErrorResponse);
}
// HTTP呼应状况码的封装,本来是依据失常特点的status特点进行解析的
protected HttpStatus getHttpStatus(Map errorAttributes) {
intsilly statusCode = (int) errorAttributes.get("status");
return HttpStatus.valueOf(statusCode);
}

确认三点:

  1. 最终封装到呼应体的目标来源于DefaultErrorWebExceptionHandler#getErrorAttributes(),而且成果是一个Map实例转换成的字节序列。
  2. 本来的RouterFunction完结只支撑HTML格局回来,咱们需求修改为JSON格局回来(或许说支撑一切格局回来)。
  3. DefaultErrorWebExceptionHandler#getHttpStatus()是呼应状况码的封装,本来的逻辑是依据失常特点getErrorAttributes()的status特点进行解析的。

自定义的JsonErrorWebExceptionHandler如下:

public class JsonErrorWebExceptionHandler extends DefaultErrorWebExceptionHandler {
public JsonErrorWebExceptionHandler(ErrorAttributes errorAttributes,
ResourceProperties resourceProperties,
ErrorProperties errorProperties,
ApplicationContext ap曹祖瑜plicationContext) {
super(errorAttributes, resourceProperties, errorProperties, appl北京天安门icationContext);
}
@Override
protected Map getErrorAttributes(ServerRequest request, boolean includeStackTrace) {
// 这儿其实能够依据失常类型进行定制化逻辑
Throwable error = super.getError(request);
Map errorAttributes = new HashMap<>(8);
errorAttributes.put("message", error.getMessage());
errorAttributes.put("code", HttpStatus.INTERNAL_SERVER_ERROR.value());
errorAttributes.put("method", request.methodName());
errorAttributes.put兰州三爱整形医院("path", request.path());
return errorAttributesarc;
}
@Override
protected RouterFunction getRoutingFunction(ErrorAttributes errorAttributes) {
return RouterFunctions.route(RequestPredicates.all(), this::renderErrorResponse);
}
@Override
protected HttpStatus getHttpStatus(Map errorAttributes) {
// 这儿其实能够依据errorAttributes里边的特点定制HTTP呼应码
return HttpStatus.INTERNAL_SERVER_ERROR;
}
}

装备类CustomErrorWebFluxAutoConfiguration增加JsonErrorWebExceptionHandler:

@Bean
@ConditionalOnMissingBean(value = ErrorWebExceptionHandler.class, search = SearchStrategy.CURRENT)
@Order(-1)
public ErrorWebExceptionHand网管哥ler errorWebExceptionHandler(ErrorAttributes errorAttributes) {
JsonErrorWebExceptionHandler exceptionHandler = new JsonErrorWebExceptionHandler(
errorAttributes,
reso韩国女主urceProperties,
this.serverProperties.getError(),
applicationContext);
exceptionHandler.setViewResolvers(this.viewResolvers);
exceptionHandler.setMessageWriters(this.serverCodecConfigurer.getWriters());
exceptionHandler.setMessageReaders(this.serverCodecConfigurer.getReaders());
return exceptionHandler;
}

很简单,这儿把失常的HTTP呼应状况码共同为HttpStatus.INTERNAL_SERVER_ERROR(500),改造的东西并不多,只需了解本来失常处理的上下文逻辑即可。

测验

测验场景一:只发动网关,下流服务不发动的状况下直接调用下流服务:

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
publi头孢克肟胶囊c class ErrorGlobalFilter implements GlobalFilter {
@Override
public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
int i = 1/0;
return chain.filter(exchange);
}
}
curl http://localhost:9090/order/host
// 呼应成果
{"path":"/order/host","code":500,"message":"/ by zero","method":"GET"}

呼应成果和定制的逻辑共同,而且后台的日志也打印了对应的失常仓库。

小结

笔者一向以为,做失常分类和依照分类处理是工程里边非常重要的一环。笔者在地点公司担任的体系中,坚持完结失常分类捕获,主要是需求区别能够重试补偿以及无法重试需求及时预警的失常,这姿态才干针对可康复失常定制自愈逻辑,对不能康复的失常及时预警和人为介入。所以,Spring Cloud Gateway这个技能栈也有必要调研其自定义失常的处理逻辑。

热门
最新
推荐
标签