使用 WebFlux 调用 Restful 服务的错​​误处理示例

问题描述

我正在寻找使用 WebFlux 进行错误处理的简单示例。我在网上阅读了很多东西,但找不到适合我想要的东西。

我正在使用 Spring Boot 2.45

我正在调用这样的服务:

Mono<ResponSEObject> mono = webClient.post()
   .uri(url.toString())
   .header("Authorization",authToken)
   .body(Mono.just(contract),contract.getClass())
   .retrieve()
   .bodyToMono(ResponSEObject.class);

我所有的服务都返回反序列化为 RespoSEObject 的 Json,看起来像这样:

"success" : true,"httpStatus": 200,"messages" : [
   "informational message or,if not 200,then error messages"
],result: {
   "data": {}
}

data 只是作为服务调用结果的对象的映射。 如果有错误,显然success 是假的。

当我最终执行 ResponSEObject response = mono.block() 时,我希望每次都获得一个 ResponSEObject,即使出现错误也是如此。即使我的服务返回 400 的 http 状态,我的服务也会返回一个 ResponSEObject,但 WebFlux 似乎拦截了它并抛出异常。显然,也可能有 400 和 500 错误甚至没有调用服务。但是我仍然想将我收到的任何消息包装到一个 ResponSEObject 中。如何消除所有异常并始终返回 ResponSEObject?

更新 只是想澄清一下,该服务本身不是 Reactive Webflux 服务。 不是返回一个 Mono。相反,它正在调用其他 Restful 服务,我想使用 Webflux 来做到这一点。所以我所做的就是调用外部服务,然后这个服务做了一个block()。在大多数情况下,我会调用多个服务,然后执行 Mono.zip 并调用 block() 以等待所有服务。

这似乎是我想要做的:Spring Webflux : Webclient : Get body on error,但仍然无法让它工作。不确定什么是 exchange()

解决方法

处理此问题的正确方法是通过 .onErrorResume,它允许您在发生任何错误时使用函数订阅后备发布者。您可以查看生成的异常并返回自定义回退响应。

你可以这样做:

Mono<ResponseObject> mono = webClient.post()
   .uri(url.toString())
   .header("Authorization",authToken)
   .bodyValue(contract)
   .exchangeToMono(response -> {
      if (response.statusCode().equals(HttpStatus.OK)) {
          return response.bodyToMono(ResponseObject.class);
      }
      else if (response.statusCode().is4xxClientError()) {
          return response.bodyToMono(ResponseObject.class);
      }
      else {
          Mono<WebClientResponseException> wcre = response.createException();
          // examine wcre and create custom ResponseObject

          ResponseObject customRO = new ResponseObject();
          customRO.setSuccess(false);
          customRO.setHttpStatus(response.rawStatusCode());
          // you can set more default properties in response here
          return Mono.just( customRO );
      }
   });

此外,您不应在 Java 代码的任何地方使用 .block()。只需确保从您的 REST 控制器返回 Mono<ResponseObject>。如果您想在返回客户端之前检查响应,您可以在管道末尾(紧跟在 .map() 处理程序之后)的 .onErrorResume 处理程序中执行此操作

   .map(response -> {
      // examine content of response

      // in the end just return it
      return response;
   });