1

我正在寻找一个使用 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": {}
}

数据只是服务调用结果的对象映射。如果有错误,显然成功是错误的。

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

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

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

4

1 回答 1

1

Correct way of handling this is via .onErrorResume that allows you to subscribe to a fallback publisher using a function, when any error occurs. You can look at the generated exception and return a custom fallback response.

You can do something like this:

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 );
      }
   });

Moreover, you should not be using .block() anywhere in your Java code. Just make sure to return a Mono<ResponseObject> from your REST controller. If you want to examine response before returning to client you can do so in a .map() hander like this at the end of pipeline (right after .onErrorResume handler)

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

      // in the end just return it
      return response;
   });
于 2021-07-13T07:46:34.543 回答