Spring Cloud Gateway 自定义异常处理

一、背景

平时我们在Spring MVC层面做自定义异常出处理都是通过@ControllerAdvice和@ExceptionHandler自定义不同类型异常的处理逻辑,如图
在这里插入图片描述
以上只是简单的同一处理异常,具体实现方式可根据项目自定义处理,这里就不展开细说。

不过本文的重点是在网关层自定义异常,因为请求通过网关再到服务,中间难免会有未处理好的异常抛出,加上网关还有限流,熔断等功能,难免有异常抛出,这个时候我们就需要对这些异常做个处理,
Spring Cloud Gateway默认的异常处理重点是在DefaultErrorWebExceptionHandler、DefaultErrorWebExceptionHandler、ErrorWebFluxAutoConfiguration这三个 类中,不过平时我们返回到客户端的异常格式都是统一的,网关默认的异常输出格式可能不能满足我们的要求,故此我们就得改造输出。

二、代码讲解

所谓的自定义异常其实就是模仿DefaultErrorWebExceptionHandler、DefaultErrorWebExceptionHandler、ErrorWebFluxAutoConfiguration这三个 类覆盖它们的异常处理,本文主要讲解使用操作方面,故原理不在此细说!

我们通过DefaultErrorWebExceptionHandler类中发现它继承了一个抽象异常处理器AbstractErrorWebExceptionHandler,而处理器中实现了ErrorWebExceptionHandler中的handle方法,重点就是在handle方法里,故此我们直接实现ErrorWebExceptionHandler接口,重写handle方法的逻辑。(废话不多数,直接上重点代码)

这里自定义了一个全局异常处理器类GlobalGatewayExceptionHandler ,模仿DefaultErrorWebExceptionHandler和AbstractErrorWebExceptionHandler类的处理

/**
 * @description: 网关异常全局处理
 */
@Slf4j
@Getter
@Setter
public class GlobalGatewayExceptionHandler implements ErrorWebExceptionHandler {

    private List<HttpMessageReader<?>> messageReaders = Collections.emptyList();
    private List<HttpMessageWriter<?>> messageWriters = Collections.emptyList();
    private List<ViewResolver> viewResolvers = Collections.emptyList();
    private ThreadLocal<ResponseResult> threadLocal=new ThreadLocal<>();

    @Override
    public Mono<Void> handle(ServerWebExchange exchange, Throwable throwable) {
        log.error("网关异常全局处理,异常信息:{}",throwable.getMessage());
        //这里只是做个最简单的同一的异常结果输出,实际业务可根据throwable不同的异常处理不同的逻辑
        ResponseResult result = ResponseResult.businessError(ResultMessage.SERVICE_ERROR.getCode(),ResultMessage.SERVICE_ERROR.getMsg());
        threadLocal.set(result);
        ServerRequest newRequest = ServerRequest.create(exchange, this.messageReaders);
        return RouterFunctions.route(RequestPredicates.all(), this::renderErrorResponse).route(newRequest)
                .switchIfEmpty(Mono.error(throwable))
                .flatMap((handler) -> handler.handle(newRequest))
                .flatMap((response) -> write(exchange, response));
    }

    /**
     * 统一返回指定异常信息(指定json格式输出)
     * @param request
     * @return
     */
    protected Mono<ServerResponse> renderErrorResponse(ServerRequest request){
        return ServerResponse.status(ResultMessage.SERVICE_ERROR.getCode())
                .contentType(MediaType.APPLICATION_JSON)
                .body(BodyInserters.fromValue(threadLocal.get()));
    }

 	/**
     * 参考DefaultErrorWebExceptionHandler
     */
    private Mono<? extends Void> write(ServerWebExchange exchange, ServerResponse response) {
        exchange.getResponse().getHeaders().setContentType(response.headers().getContentType());
        return response.writeTo(exchange, new ResponseContext());
    }

	 /**
     * 参考DefaultErrorWebExceptionHandler
     */
    private class ResponseContext implements ServerResponse.Context {
        private ResponseContext() {
        }

        @Override
        public List<HttpMessageWriter<?>> messageWriters() {
            return GlobalGatewayExceptionHandler.this.messageWriters;
        }

        @Override
        public List<ViewResolver> viewResolvers() {
            return GlobalGatewayExceptionHandler.this.viewResolvers;
        }
    }
}

GlobalGatewayExceptionConfig 类就是模仿ErrorWebFluxAutoConfiguration类中的处理

/**
 * @description: 网关异常配置,覆盖默认的异常处理
 */
@Configuration
public class GlobalGatewayExceptionConfig {

    @Primary
    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public ErrorWebExceptionHandler errorWebExceptionHandler(ObjectProvider<List<ViewResolver>> viewResolversProvider,
                                                             ServerCodecConfigurer serverCodecConfigurer){
        GlobalGatewayExceptionHandler globalGatewayExceptionHandler =new GlobalGatewayExceptionHandler();
        globalGatewayExceptionHandler.setViewResolvers(viewResolversProvider.getIfAvailable(Collections::emptyList));
        globalGatewayExceptionHandler.setMessageWriters(serverCodecConfigurer.getWriters());
        globalGatewayExceptionHandler.setMessageReaders(serverCodecConfigurer.getReaders());
        return globalGatewayExceptionHandler;
    }
}

最终的输出结果就是我们自定义的异常输出
{
“code”: 500,
“msg”: “该服务无法使用”,
“data”: null
}

以上示例只是代码片段,只讲解具体实现逻辑,具体实现方式可根据自己的情况定义,实现的方式有很多种,上面讲解的是直接实现ErrorWebExceptionHandler 中的handle方法,如果有兴趣的朋友也可以继承DefaultErrorWebExceptionHandler或者AbstractErrorWebExceptionHandler,然后重写它们的方法覆盖它们的逻辑,怎么喜欢怎么来,各位自己决定。具体就讲解这么多,有任何错误和建议,欢迎留言!

注:如果本博文有任何错误和建议,欢迎留言,共同学习,共同进步!

Spring Cloud Gateway 提供了一种全局异常处理机制,它允许你在整个网关链路中统一管理和捕获错误。通过使用 `GlobalExceptionHandler` 或自定义拦截器,你可以配置如何处理来自下游服务的响应失败、路由错误或其他非预期的状况。 通常,全局异常处理的过程包括以下几个步骤: 1. **创建全局异常处理器**:在 Spring Boot 应用中,你可以创建一个实现了 `GlobalExceptionHandler` 接口的类,并覆盖其 `handle` 方法。这个方法接收 `WebExchange` 和 `Throwable` 参数,你可以在这里定制错误处理逻辑,如记录日志、返回统一的错误响应等。 ```java @Component public class GlobalExceptionHandler implements GlobalExceptionHandler { @Override public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) { // 捕获异常并返回适当的响应 return handleException(exchange, new ErrorResponse(HttpStatus.INTERNAL_SERVER_ERROR.value(), ex.getMessage())); } } ``` 2. **应用配置**:在 Gateway 的配置中启用全局异常处理,并指定你的全局处理器类。例如,在 YAML 配置中添加如下内容: ```yaml spring: cloud: gateway: global-error-handler: com.example.GlobalExceptionHandler ``` 3. **错误响应处理**:`handleException` 方法可以根据需要决定返回何种状态码和错误信息给客户端。常见的做法是返回一个统一的 JSON 格式,比如包含错误码和描述的消息。 当你设置好全局异常处理后,无论内部服务出现何种类型的异常,Spring Cloud Gateway 都会按照你设定的方式进行处理,提供一个一致的服务响应。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值