Spring 5 Reactive 中的 HTTP 响应异常处理
HTTP Response Exception Handling in Spring 5 Reactive
我正在使用 Spring Boot 2 和 Spring 5 以及 WebFlux 反应式启动器开发一些反应式微服务。
我面临以下问题:我想处理通过调用另一个 REST 服务收到的所有 HTTP 状态,并在收到一些错误的 HTTP 状态时抛出异常。例如,当我调用一个端点并收到 404 HTTP 状态时,我想抛出一个异常并在某些 ExceptionHandler class 中处理该异常,就像它在 Spring 4 中的方式一样@ControllerAdvice
.
正确的做法是什么?希望收到一些好的建议。
我认为您正在寻找的是 WebFluxResponseStatusExceptionHandler
检查此 reference。
In the WebHandler API, a WebExceptionHandler can be used to to handle
exceptions from the chain of WebFilter's and the target WebHandler.
When using the WebFlux Config, registering a WebExceptionHandler is as
simple as declaring it as a Spring bean, and optionally expressing
precedence via @Order on the bean declaration or by implementing
Ordered.
This example 可能有帮助,我自己没试过。
@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.");
}
}
这可以在两个独立的部分中解决。
如何将 WebClient 收到的 HTTP 404 响应转换为自定义异常
使用 WebClient
时,您可以从远程服务接收 HTTP 404 响应。默认情况下,所有 4xx
和 5xx
客户端响应都将变成 WebClientResponseException
。因此,您可以直接在 WebFlux 应用程序中处理这些异常。
如果您只想将 404 响应变成自定义例外,您可以执行以下操作:
WebClient webClient = //...
webClient.get().uri("/persons/1")
.retrieve()
.onStatus(httpStatus -> HttpStatus.NOT_FOUND.equals(httpStatus),
clientResponse -> Mono.error(new MyCustomException()))
.bodyToMono(...);
这显然是在每个客户调用的基础上完成的。
您可以使用 ExchangeFilterFunction
以更可重用的方式实现相同的目的,您可以在 WebClient
实例上一劳永逸地设置,如下所示:
WebClient.builder().filter(myExchangeFilterFunction)...
如何处理 WebFlux 应用程序中的自定义异常
使用带有注释的 Spring WebFlux,您可以使用带有 @ExceptionHandler
注释的方法处理异常(参见 Spring Framework reference documentation)。
注意:使用 WebExceptionHandler
是可能的,但它的级别很低,因为你在那里没有 high-level 支持:你需要在没有任何支持的情况下手动编写带有缓冲区的响应用于序列化。
我正在使用 Spring Boot 2 和 Spring 5 以及 WebFlux 反应式启动器开发一些反应式微服务。
我面临以下问题:我想处理通过调用另一个 REST 服务收到的所有 HTTP 状态,并在收到一些错误的 HTTP 状态时抛出异常。例如,当我调用一个端点并收到 404 HTTP 状态时,我想抛出一个异常并在某些 ExceptionHandler class 中处理该异常,就像它在 Spring 4 中的方式一样@ControllerAdvice
.
正确的做法是什么?希望收到一些好的建议。
我认为您正在寻找的是 WebFluxResponseStatusExceptionHandler
检查此 reference。
In the WebHandler API, a WebExceptionHandler can be used to to handle exceptions from the chain of WebFilter's and the target WebHandler. When using the WebFlux Config, registering a WebExceptionHandler is as simple as declaring it as a Spring bean, and optionally expressing precedence via @Order on the bean declaration or by implementing Ordered.
This example 可能有帮助,我自己没试过。
@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.");
}
}
这可以在两个独立的部分中解决。
如何将 WebClient 收到的 HTTP 404 响应转换为自定义异常
使用 WebClient
时,您可以从远程服务接收 HTTP 404 响应。默认情况下,所有 4xx
和 5xx
客户端响应都将变成 WebClientResponseException
。因此,您可以直接在 WebFlux 应用程序中处理这些异常。
如果您只想将 404 响应变成自定义例外,您可以执行以下操作:
WebClient webClient = //...
webClient.get().uri("/persons/1")
.retrieve()
.onStatus(httpStatus -> HttpStatus.NOT_FOUND.equals(httpStatus),
clientResponse -> Mono.error(new MyCustomException()))
.bodyToMono(...);
这显然是在每个客户调用的基础上完成的。
您可以使用 ExchangeFilterFunction
以更可重用的方式实现相同的目的,您可以在 WebClient
实例上一劳永逸地设置,如下所示:
WebClient.builder().filter(myExchangeFilterFunction)...
如何处理 WebFlux 应用程序中的自定义异常
使用带有注释的 Spring WebFlux,您可以使用带有 @ExceptionHandler
注释的方法处理异常(参见 Spring Framework reference documentation)。
注意:使用 WebExceptionHandler
是可能的,但它的级别很低,因为你在那里没有 high-level 支持:你需要在没有任何支持的情况下手动编写带有缓冲区的响应用于序列化。