每天多学一点点~
话不多说,这就开始吧…
最近一周在弄spring-cloud的基础架构,试着在网关这一层做统一的异常处理,返回统一信息,这样对前端比较友好。一开始无头绪,试着慢慢分析,这里做一下总结。
说到底网关也是个单体的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方法。
于是乎便有了思路,如下:
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;}
}
服务 | 端口 |
---|---|
boke-gateway | 8888 |
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的全局异常
世上无难事,只怕有心人,每天积累一点点,fighting!!!
本文发布于:2024-01-31 12:29:39,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/170667537928520.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |