栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Spring Cloud Gateway 全局通用异常处理

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Spring Cloud Gateway 全局通用异常处理

为什么需要全局异常处理

在传统 Spring Boot 应用中, 我们 @ControllerAdvice 来处理全局的异常,进行统一包装返回


// 摘至 spring cloud alibaba console 模块处理
@ControllerAdvice
public class ConsoleExceptionHandler {

    @ExceptionHandler(AccessException.class)
    private ResponseEntity handleAccessException(AccessException e) {
 return ResponseEntity.status(HttpStatus.FORBIDDEN).body(e.getErrMsg());
    }
}

例如: ③ 处应用调用数据库异常,通过 @ControllerAdvice 包装异常请求响应给客户端

但在微服务架构下, 例如 ② 处 网关调用业务微服务失败(转发失败、调用异常、转发失败),在应用设置的 @ControllerAdvice 将失效,因为流量根本没有转发到应用上处理。

如上图: 模拟所有路由断言都不匹配 404 , 和 spring boot 默认保持一致的错误输出页面。 显然我们在网关同样配置 @ControllerAdvice 是不能解决问题,因为 spring cloud gateway 是基于 webflux 反应式编程。

解决方法 默认处理流程
  • ExceptionHandlingWebHandler 作为 spring cloud gateway 最核心 WebHandler 的一部分会进行异常处理的过滤
public class ExceptionHandlingWebHandler extends WebHandlerDecorator {
	@Override
	public Mono handle(ServerWebExchange exchange) {
		Mono completion;
		try {
			completion = super.handle(exchange);
		}
		catch (Throwable ex) {
			completion = Mono.error(ex);
		}

     // 获取全局的 WebExceptionHandler 执行
		for (WebExceptionHandler handler : this.exceptionHandlers) {
			completion = completion.onErrorResume(ex -> handler.handle(exchange, ex));
		}
		return completion;
	}
}
  • 默认实现 DefaultErrorWebExceptionHandler

public class DefaultErrorWebExceptionHandler  {

	@Override
	protected RouterFunction getRoutingFunction(ErrorAttributes errorAttributes) {
     // 根据客户端 `accpet` 请求头决定返回什么资源,如上浏览器返回的是 页面
		return route(acceptsTextHtml(), this::renderErrorView).andRoute(all(), this::renderErrorResponse);
	}
}

// 模拟指定 `accpet` 情况
curl --location --request GET 'http://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

@Slf4j
@Order(-1)
@RequiredArgsConstructor
public class GlobalExceptionConfiguration implements ErrorWebExceptionHandler {
	private final ObjectMapper objectMapper;

	@Override
	public Mono handle(ServerWebExchange exchange, Throwable ex) {
		ServerHttpResponse response = exchange.getResponse();

		if (response.isCommitted()) {
			return Mono.error(ex);
		}

		// header set
		response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
		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.failed(ex.getMessage())));
					} 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
  • 具体实现代码参考:https://gitee.com/log4j/pig
转载请注明:文章转载自 www.mshxw.com
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号