【问题标题】:Example of error handling calling Restful services with WebFlux使用 WebFlux 调用 Restful 服务的错​​误处理示例
【发布时间】:2021-07-13 00:19:00
【问题描述】:

我正在寻找一个使用 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,即使出现错误。我的服务返回一个 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() 是什么

【问题讨论】:

    标签: spring-boot spring-webflux spring-webclient webflux


    【解决方案1】:

    处理此问题的正确方法是通过.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&lt;ResponseObject&gt;。如果您想在返回客户端之前检查响应,您可以在管道末尾的 .map() 处理程序中执行此操作(就在.onErrorResume 处理程序之后)

       .map(response -> {
          // examine content of response
    
          // in the end just return it
          return response;
       });
    

    【讨论】:

    • 谢谢,让我玩这个。当您说我不应该在 Java 代码的任何地方使用 block() 时,您是什么意思?我认为这是本质上订阅流程以便它实际执行的方式。如何启动 Webflux 代码然后获得响应?
    • 我想我明白你不使用 block() 的意思。我正在编辑我原来的问题,以澄清我在这里做什么。如果我从未到达终点,您的解决方案将有效。例如,如果出现网络错误并且我收到 500 响应,这让我将异常包装在我的 ResponseObject 中。但是,如果我的服务 does 返回一个响应对象,但由于参数错误或类似情况而返回 400,我该如何处理。我想使用返回的 ResponseObject,而不是创建一个新的
    • 哎呀,我打算编辑我​​原来的问题,但我编辑了一条评论。不是故意的,不知道如何取消它
    • 这似乎是我想做的:stackoverflow.com/questions/44593066/…
    • 不确定该答案如何帮助您,因为您想在出现错误时从客户端获取响应。我会为此做进一步的更新。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-06-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多