Springboot WebFlux全局异常处理(RouterFunction路由)

264 阅读1分钟

前言

之前 spring web 常用的全局异常处理方法如下:

@ControllerAdvice
public class GlobalExceptionHandler {

  @ExceptionHandler(MyException.class)
 // 处理函数...

}

在 webFlux 基于注解的路由编程方法(eg: @GetMapping()),上述方法中仍然可用

但如果想尝试新的 RouterFunction 路由方式,方法抛出的异常不会被全局异常抓到,而是走了 webFlux默认的异常处理,显示一大堆信息

方案一

  • 只需要像注册接口路由 RouterFunction 一样,注册一个bean
    @Bean
    WebFilter reqExceptionToBadRequest() {
        return (exchange, next) -> next.filter(exchange)
                .onErrorResume(MyException.class, e -> {
                    ServerHttpResponse response = exchange.getResponse();
                    response.setStatusCode(HttpStatus.BAD_REQUEST);
                    return response.setComplete();
                });
    }
  • 上面这个过滤器会捕获MyException,自定义处理后响应信息

上面只修改了状态码,如果想要自定义响应体,参考下面:

    private byte[] jsonToByteArray(Object json) {
        try {
            return new ObjectMapper().writeValueAsBytes(json);
        } catch (JsonProcessingException ex) {
            // 可以自定义其他逻辑,这里简单起见
            return ex.getMessage().getBytes();
        }
    }

    @Bean
    WebFilter reqExceptionToBadRequest() {
        return (exchange, next) -> next.filter(exchange)
                .onErrorResume(WebRequestException.class, e -> {
                    ServerHttpResponse response = exchange.getResponse();

                    response.setStatusCode(HttpStatus.BAD_REQUEST);
                    response.getHeaders().add(
                            "Content-Type", "application/json"
                    );

                    var resp = Map.of("message", "自定义信息");


                    DataBuffer buffer = exchange.getResponse().bufferFactory().wrap(
                            jsonToByteArray(resp)
                    );

                    return response.writeWith(Mono.just(buffer));
                });
    }

方案二

  • 也可以对只特定的路由生效
@Bean
RouterFunction<ServerResponse> route() {
    return RouterFunctions
            .route(GET("/foo"), request -> Mono.error(new DataNotFoundException()))
            .andRoute(GET("/bar"), request -> Mono.error(new DataNotFoundException()))
            .filter(dataNotFoundToBadRequest());
}

private HandlerFilterFunction<ServerResponse, ServerResponse> dataNotFoundToBadRequest() {
    return (request, next) -> next.handle(request)
            .onErrorResume(DataNotFoundException.class, e -> ServerResponse.badRequest().build());
}

参考: