Spring 5 Reactive 中的 HTTP 响应异常处理

Din*_*dan 14 java exception spring-boot spring-webflux

我正在使用 Spring Boot 2 和 Spring 5 和 WebFlux 反应式启动器开发一些反应式微服务。

我面临以下问题:我想处理通过调用另一个 REST 服务收到的所有 HTTP 状态,并在收到一些错误的 HTTP 状态时抛出异常。例如,当我调用端点并收到 404 HTTP 状态时,我想抛出一个异常,并且该异常将在某些 ExceptionHandler 类中处理,就像在 Spring 4 中使用@ControllerAdvice.

这样做的正确方法是什么?希望得到一些好的建议。

Bri*_*zel 13

这可以通过两个独立的部分来解决。

如何将 WebClient 接收到的 HTTP 404 响应转换为自定义异常

使用 时WebClient,您可以从远程服务接收 HTTP 404 响应。默认情况下,所有4xx5xx客户端响应都将转换为WebClientResponseException. 所以你可以直接在你的 WebFlux 应用程序中处理这些异常。

如果您只想将 404 响应转换为自定义异常,您可以执行以下操作:

WebClient webClient = //...
webClient.get().uri("/persons/1")
  .retrieve()
  .onStatus(httpStatus -> HttpStatus.NOT_FOUND.equals(httpStatus),
                        clientResponse -> Mono.error(new MyCustomException()))
  .bodyToMono(...);
Run Code Online (Sandbox Code Playgroud)

这显然是在每个客户端调用的基础上完成的。

您可以以更可重用的方式实现相同的目的ExchangeFilterFunction,您可以在这样的WebClient实例上一劳永逸地设置它:

WebClient.builder().filter(myExchangeFilterFunction)...
Run Code Online (Sandbox Code Playgroud)

如何处理 WebFlux 应用程序中的自定义异常

使用带有注解的 Spring WebFlux,您可以使用带有注解的方法处理异常@ExceptionHandler(请参阅Spring Framework 参考文档)。

注意:使用 aWebExceptionHandler是可能的,但它是相当低级别的,因为您在那里没有高级支持:您需要手动编写带有缓冲区的响应,而不支持任何序列化。


Pär*_*son 5

我认为您正在寻找的是WebFluxResponseStatusExceptionHandler检查此以供参考

在 WebHandler API 中,WebExceptionHandler 可用于处理来自 WebFilter 链和目标 WebHandler 的异常。使用 WebFlux Config 时,注册 WebExceptionHandler 就像将其声明为 Spring bean 一样简单,并可选择通过 bean 声明中的 @Order 或通过实现 Ordered 来表达优先级。

这个例子可能有帮助,我自己没试过。

@Component
@Order(-2)
class RestWebExceptionHandler implements WebExceptionHandler{

    @Override
    public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
        if (ex instanceof PostNotFoundException) {
            exchange.getResponse().setStatusCode(HttpStatus.NOT_FOUND);

            // marks the response as complete and forbids writing to it
            return exchange.getResponse().setComplete();
        }
        return Mono.error(ex);
    }
}

class PostNotFoundException extends RuntimeException {
    PostNotFoundException(String id) {
        super("Post:" + id + " is not found.");
    }
}
Run Code Online (Sandbox Code Playgroud)