SpringCloudGateway全局通⽤异常处理的实现
为什么需要全局异常处理
在传统 Spring Boot 应⽤中,我们 @ControllerAdvice 来处理全局的异常,进⾏统⼀包装返回
// 摘⾄ spring cloud alibaba console 模块处理
@ControllerAdvice
public class ConsoleExceptionHandler {
@ExceptionHandler(AccessException.class)
private ResponseEntity<String> handleAccessException(AccessException e) {
return ResponseEntity.status(HttpStatus.FORBIDDEN).ErrMsg());
}
}
例如:③处应⽤调⽤数据库异常,通过 @ControllerAdvice 包装异常请求响应给客户端
但在微服务架构下,例如②处⽹关调⽤业务微服务失败(转发失败、调⽤异常、转发失败),在应⽤设置的 @ControllerAdvice 将失效,因为流量根本没有转发到应⽤上处理。
如上图:模拟所有路由断⾔都不匹配 404 , 和 spring boot 默认保持⼀致的错误输出页⾯。显然我们在⽹
关同样配置 @ControllerAdvice 是不能解决问题,因为 spring cloud gateway 是基于 webflux 反应式编程。
springcloud集成log4j2解决⽅法
默认处理流程
ExceptionHandlingWebHandler 作为 spring cloud gateway 最核⼼ WebHandler 的⼀部分会进⾏异常处理的过滤
public class ExceptionHandlingWebHandler extends WebHandlerDecorator {
@Override
public Mono<Void> handle(ServerWebExchange exchange) {
Mono<Void> completion;
try {
completion = super.handle(exchange);
}
catch (Throwable ex) {
completion = (ex);
}
// 获取全局的 WebExceptionHandler 执⾏
for (WebExceptionHandler handler : ptionHandlers) {
completion = ErrorResume(ex -> handler.handle(exchange, ex));
}
return completion;
}
}
默认实现 DefaultErrorWebExceptionHandler
public class DefaultErrorWebExceptionHandler {
@Override
protected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) {
// 根据客户端 `accpet` 请求头决定返回什么资源,如上浏览器返回的是页⾯
return route(acceptsTextHtml(), this::renderErrorView).andRoute(all(), this::renderErrorResponse);
}
}
// 模拟指定 `accpet` 情况
curl --location --request GET 'localhost:9999/adminx/xx' \ 18:09:23
--header 'Accept: application/json'
{"timestamp":"2020-05-24 18:09:24","path":"/adminx/xx","status":404,"error":"Not Found","message":null,"requestId":"083c48e3-2"}⏎
重写 ErrorWebExceptionHandler
/**
* @author lengleng
* @date 2020/5/23
* <p>
* ⽹关异常通⽤处理器,只作⽤在webflux 环境下 , 优先级低于 {@link ResponseStatusExceptionHandler} 执⾏
*/
@Slf4j
@Order(-1)
@RequiredArgsConstructor
public class GlobalExceptionConfiguration implements ErrorWebExceptionHandler {
private final ObjectMapper objectMapper;
@Override
public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
ServerHttpResponse response = Response();
if (response.isCommitted()) {
(ex);
}
// header set
if (ex instanceof ResponseStatusException) {
response.setStatusCode(((ResponseStatusException) ex).getStatus());
}
return response
.writeWith(Mono.fromSupplier(() -> {
DataBufferFactory bufferFactory = response.bufferFactory();
try {
return bufferFactory.wrap(objectMapper.writeValueAsBytes(R.Message())));
} catch (JsonProcessingException e) {
log.warn("Error writing response", ex);
return bufferFactory.wrap(new byte[0]);
}
}));
}
}
总结
重写的 DefaultErrorWebExceptionHandler 优先级⼀定要⼩于内置 ResponseStatusExceptionHandler 经过它处理的获取对应错误类的响应码
其他扩展可以参考 SentinelBlockExceptionHandler sentinel 整合⽹关的处理,不过整体和默认的异常处理没有什么区别
基础环境说明:Spring Cloud Hoxton.SR4 & Spring Boot 2.3.0
具体实现代码参考:gitee/log4j/pig
到此这篇关于Spring Cloud Gateway全局通⽤异常处理的实现的⽂章就介绍到这了,更多相关Spring Cloud Gateway全局异常内容请搜索以前的⽂章或继续浏览下⾯的相关⽂章希望⼤家以后多多⽀持!
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论