gateWay全局异常配置

阅读: 评论:0

gateWay全局异常配置

gateWay全局异常配置

gateWay全局异常配置-----代码+分析思路

每天多学一点点~
话不多说,这就开始吧…

文章目录

  • gateWay全局异常配置-----代码+分析思路
  • 1.前言
  • 2.思考思路
  • 3.代码实现
  • 4.测试
  • 5.结语

1.前言

最近一周在弄spring-cloud的基础架构,试着在网关这一层做统一的异常处理,返回统一信息,这样对前端比较友好。一开始无头绪,试着慢慢分析,这里做一下总结。

2.思考思路

说到底网关也是个单体的springboot项目,springboot是自动装配,在没有引入网关之前,其处理统一异常的类在
org.springframework.boot.autoconfigure.ErrorMvcAutoConfiguration

而 网关 底层 是 webflux 的响应式编程,于是,找到了 reactive是包
org.springframework.boot.ErrorWebFluxAutoConfiguration(接触spring比较多的童鞋,一般都会直接看AutoConfigurationxxxx),

webflux的错误web自动装配,点进去这个类,发现如下方法 errorWebExceptionHandler,

	@Bean@ConditionalOnMissingBean(value = ErrorWebExceptionHandler.class, search = SearchStrategy.CURRENT)@Order(-1)public ErrorWebExceptionHandler errorWebExceptionHandler(ErrorAttributes errorAttributes) {// 用的是DefaultErrorWebExceptionHandler,重写后注入我们自定义的ErrorWebExceptionHandlerDefaultErrorWebExceptionHandler exceptionHandler = new DefaultErrorWebExceptionHandler(sourceProperties, Error(), this.applicationContext);exceptionHandler.setViewResolvers(this.viewResolvers);exceptionHandler.setMessageWriters(Writers());exceptionHandler.setMessageReaders(Readers());return exceptionHandler;}

打个断点,模拟一下异常,发现 果真 断点进来了,最后一步步调试,发现其调用了
org.springframework.boot.DefaultErrorWebExceptionHandler#renderErrorResponse方法。

于是乎便有了思路,如下:

  1. 复制ErrorWebFluxAutoConfiguration 类,名称为 ExceptionAutoConfiguration,重写其errorWebExceptionHandler方法 ,然后定义自己的CustomErrorWebExceptionHandler
  2. 写一个自己的CustomErrorWebExceptionHandler类, 继承 DefaultErrorWebExceptionHandlerrenderErrorResponse()方法和getRoutingFunction() 。(原本DefaultErrorWebExceptionHandler中这两个方法都是返回错误页面的,我们这里只需要重新塞入自定义的handler就行)
  3. 自定义GateWayExceptionHandlerAdvice,返回统一json格式

3.代码实现

GateWayExceptionHandlerAdvice 类

/* ━━━━━━佛祖保佑━━━━━━*                  ,;,,;*                ,;;'(    社*      __      ,;;' '    会*   /'  ''~~'~'  /'.)  主* ,;(      )    /  |.     义*,;'     /-.,,(   )     码*     ) /       ) / )|    农*     ||        ||  )*     (_       (_* ━━━━━━永无BUG━━━━━━* @author :zjq* @date :2020/7/21 16:14* @description: TODO  自定义网关异常* @version: V1.0* @slogan: 天下风云出我辈,一入代码岁月催*/
@Slf4j
@Component
public class GateWayExceptionHandlerAdvice {/*** 统一 异常** @param throwable* @return*/@ExceptionHandler(value = {Exception.class})public CommonResult handle(Throwable throwable) {if (throwable instanceof SignatureException) {return signHandle((SignatureException) throwable);} else if (throwable instanceof NotFoundException) {return notFoundHandle((NotFoundException) throwable);} else if (throwable instanceof ResponseStatusException) {return handle((ResponseStatusException) throwable);} else if (throwable instanceof GateWayException) {return badGatewayHandle((GateWayException) throwable);} else if (throwable instanceof ConnectTimeoutException) {return timeoutHandle((ConnectTimeoutException) throwable);} else {return CommonResult.failed();}}/*** 401 校验 异常** @param ex* @return*/@ExceptionHandler(value = {SignatureException.class})@ResponseStatus(HttpStatus.UNAUTHORIZED)public CommonResult signHandle(SignatureException ex) {("SignatureException:{}", ex.getMessage());return CommonResult.failed(ResultCode.UNAUTHORIZED);}/*** 404 服务未找到 异常** @param ex* @return*/@ExceptionHandler(value = {NotFoundException.class})@ResponseStatus(HttpStatus.NOT_FOUND)public CommonResult notFoundHandle(NotFoundException ex) {("not found exception:{}", ex.getMessage());return CommonResult.failed(ResultCode.NOT_FOUND);}/*** 500   其他服务 异常** @param ex* @return*/@ExceptionHandler(value = {ResponseStatusException.class})@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)public CommonResult handle(ResponseStatusException ex) {("ResponseStatusException:{}", ex.getMessage());return CommonResult.failed(ResultCode.UNAUTHORIZED);}/*** 502 错误网关 异常** @param ex* @return*/@ExceptionHandler(value = {GateWayException.class})@ResponseStatus(HttpStatus.BAD_GATEWAY)public CommonResult badGatewayHandle(GateWayException ex) {("badGateway exception:{}", ex.getMessage());return CommonResult.failed(ResultCode.BAD_GATEWAY);}/*** 504 网关超时 异常** @param ex* @return*/@ExceptionHandler(value = {ConnectTimeoutException.class})@ResponseStatus(HttpStatus.GATEWAY_TIMEOUT)public CommonResult timeoutHandle(ConnectTimeoutException ex) {("connect timeout exception:{}", ex.getMessage());return CommonResult.failed(ResultCode.GATEWAY_CONNECT_TIME_OUT);}
}

CustomErrorWebExceptionHandler 类

/* ━━━━━━佛祖保佑━━━━━━*                  ,;,,;*                ,;;'(    社*      __      ,;;' '    会*   /'  ''~~'~'  /'.)  主* ,;(      )    /  |.     义*,;'     /-.,,(   )     码*     ) /       ) / )|    农*     ||        ||  )*     (_       (_* ━━━━━━永无BUG━━━━━━* @author :zjq* @date :2020/7/21 16:14* @description: TODO  重写webflux 的 DefaultErrorWebExceptionHandler* @version: V1.0* @slogan: 天下风云出我辈,一入代码岁月催*/
@Slf4j
public class CustomErrorWebExceptionHandler extends DefaultErrorWebExceptionHandler {@Autowiredprivate GateWayExceptionHandlerAdvice gateWayExceptionHandlerAdvice;public CustomErrorWebExceptionHandler(ErrorAttributes errorAttributes, ResourceProperties resourceProperties,ErrorProperties errorProperties, ApplicationContext applicationContext) {super(errorAttributes, resourceProperties, errorProperties, applicationContext);}@Overrideprotected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) {ute(RequestPredicates.all(), this::renderErrorResponse);}/*** 重写 异常方法 塞入自己的 gateWayExceptionHandlerAdvice** @param request* @return*/@Overrideprotected Mono<ServerResponse> renderErrorResponse(ServerRequest request) {boolean includeStackTrace = isIncludeStackTrace(request, MediaType.ALL);Map<String, Object> error = getErrorAttributes(request, includeStackTrace);Throwable throwable = getError(request);return ServerResponse.HttpStatus(error)).contentType(MediaType.APPLICATION_JSON_UTF8).body(BodyInserters.fromObject(gateWayExceptionHandlerAdvice.handle(throwable)));}
}

ExceptionAutoConfiguration 类

/* ━━━━━━佛祖保佑━━━━━━*                  ,;,,;*                ,;;'(    社*      __      ,;;' '    会*   /'  ''~~'~'  /'.)  主* ,;(      )    /  |.     义*,;'     /-.,,(   )     码*     ) /       ) / )|    农*     ||        ||  )*     (_       (_* ━━━━━━永无BUG━━━━━━* @author :zjq* @date :2020/7/21 16:14* @description: TODO   观察 网关 ErrorWebFluxAutoConfiguration 的配置 重写*                      把该该配置类copy下来,然后定义errorWebExceptionHandler的逻辑*                      写一个自定义的异常处理器* @version: V1.0* @slogan: 天下风云出我辈,一入代码岁月催*/
@Configuration
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
@ConditionalOnClass(WebFluxConfigurer.class)
@AutoConfigureBefore(WebFluxAutoConfiguration.class)
@EnableConfigurationProperties({ServerProperties.class, ResourceProperties.class})
public class ExceptionAutoConfiguration {private ServerProperties serverProperties;private ApplicationContext applicationContext;private ResourceProperties resourceProperties;private List<ViewResolver> viewResolvers;private ServerCodecConfigurer serverCodecConfigurer;public ExceptionAutoConfiguration(ServerProperties serverProperties,ResourceProperties resourceProperties,ObjectProvider<List<ViewResolver>> viewResolversProvider,ServerCodecConfigurer serverCodecConfigurer,ApplicationContext applicationContext) {this.serverProperties = serverProperties;this.applicationContext = sourceProperties = resourceProperties;this.viewResolvers = IfAvailable(() -> ptyList());this.serverCodecConfigurer = serverCodecConfigurer;}@Bean@Order(Ordered.HIGHEST_PRECEDENCE)  // 要比 ErrorWebFluxAutoConfiguration 小,表示其优先调用public ErrorWebExceptionHandler errorWebExceptionHandler(ErrorAttributes errorAttributes) {// 注入自己的 CustomErrorWebExceptionHandler 处理类DefaultErrorWebExceptionHandler exceptionHandler = new CustomErrorWebExceptionHandler(errorAttributes, sourceProperties,Error(), this.applicationContext);exceptionHandler.setViewResolvers(this.viewResolvers);exceptionHandler.setMessageWriters(Writers());exceptionHandler.setMessageReaders(Readers());return exceptionHandler;}
}

4.测试

服务端口
boke-gateway8888
boke-api(业务工程)8081

若网关工程这里出现异常,比如(下游工程未开启, System.out.println(1/0); 等等)会返回自定义json格式,出现了自定义异常。

但是,下游服务出现异常,依然会出现网关原生的格式,比如

boke-api 工程

@RequestMapping("/api")
@RestController
public class BokeApiController extends BaseController {@PostMapping("/getLog")public CommonResult getLog(@RequestBody ApiReq req) {System.out.println(1/0);return CommonResult.success(null, "调用成功");}}

所以,在下游服务 boke-api 工程 中加上 @RestControllerAdvice

/* ━━━━━━佛祖保佑━━━━━━*                  ,;,,;*                ,;;'(    社*      __      ,;;' '    会*   /'  ''~~'~'  /'.)  主* ,;(      )    /  |.     义*,;'     /-.,,(   )     码*     ) /       ) / )|    农*     ||        ||  )*     (_       (_* ━━━━━━永无BUG━━━━━━* @author :zjq* @date :2020/7/21 01:39* @description: TODO   接口层 是否需要通用接口 后续看* @version: V1.0* @slogan: 天下风云出我辈,一入代码岁月催*/
@RestControllerAdvice
public class RequestBadExceptionHandler {/*** 兜底异常捕捉** @param e* @return*/@ExceptionHandler(Exception.class)public CommonResult<String> ExepitonHandler(Exception e) {if (e instanceof NoHandlerFoundException) {return CommonResult.failed(ResultCode.NOT_FOUND);} else if (e instanceof BusinessException) {return CommonResult.failed("api接口错误: " + e.getMessage());}return CommonResult.failed();}}

再次进行测试,出现自定义异常。即,每个下游微服务,依然要配置springboot的全局异常

5.结语

世上无难事,只怕有心人,每天积累一点点,fighting!!!

本文发布于:2024-01-31 12:29:39,感谢您对本站的认可!

本文链接:https://www.4u4v.net/it/170667537928520.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:全局   异常   gateWay
留言与评论(共有 0 条评论)
   
验证码:

Copyright ©2019-2022 Comsenz Inc.Powered by ©

网站地图1 网站地图2 网站地图3 网站地图4 网站地图5 网站地图6 网站地图7 网站地图8 网站地图9 网站地图10 网站地图11 网站地图12 网站地图13 网站地图14 网站地图15 网站地图16 网站地图17 网站地图18 网站地图19 网站地图20 网站地图21 网站地图22/a> 网站地图23