繁体   English   中英

如何使用 Springboot 对 WebFlux 进行异常处理?

[英]How to do Exception Handling for WebFlux using Springboot?

我有 3 个微服务应用程序。 我正在尝试使用来自反应性 package 的 webclient 进行 2 get call async,然后在收到响应时将它们组合起来。

示例代码:(参考 - https://docs.spring.io/spring/docs/5.1.9.RELEASE/spring-framework-reference/web-reactive.html#webflux-client-synchronous

Mono<Person> personMono = client.get().uri("/person/{id}", personId)
        .retrieve().bodyToMono(Person.class);

Mono<List<Hobby>> hobbiesMono = client.get().uri("/person/{id}/hobbies", personId)
        .retrieve().bodyToFlux(Hobby.class).collectList();

Map<String, Object> data = Mono.zip(personMono, hobbiesMono, (person, hobbies) -> {
            Map<String, String> map = new LinkedHashMap<>();
            map.put("person", personName);
            map.put("hobbies", hobbies);
            return map;
        })
        .block();

我的问题是如何向 get 调用添加异常处理?

如何检查我是否得到了 404 或 204 或其他内容?

我努力了:

  1. 将.onStatus() 添加到 GET 调用
    .onStatus(HttpStatus::is4xxClientError, clientResponse ->
             Mono.error(new Data4xxException(String.format(
                "Could not GET data with id: %s from another app, due to error: 
                 %s", key, clientResponse))))
    .onStatus(HttpStatus::is5xxServerError, clientResponse ->
          Mono.error(new Data5xxException(
              String.format("For Data %s, Error Occurred: %s", key, clientResponse))))
  1. 添加异常处理程序 - 但我完全没有 controller 所以这似乎不起作用。
@ExceptionHandler(WebClientException.class)
    public Exception handlerWebClientException(WebClientException webClientException) {
        return new Data4xxException("Testing", webClientException);
    }
  1. 添加了一个 class,其中包含 ControllerAdvice 和 ExceptionHandler
@ControllerAdvice
public class WebFluxExceptionHandler {

    @ExceptionHandler(WebClientException.class)
    public Exception handlerWebClientException(WebClientException webClientException) {
        return new Data4xxException("Testing", webClientException);
    }
}

但我没有看到它们打印在 spring-boot 日志中。

Mono.zip.block() 方法只返回 null,实际上并没有抛出任何异常。

如何让 zip 方法抛出异常而不返回 null?

这样做的方法是通过以下方式使用 onErrorMap:

Mono<Person> personMono = client.get()
.uri("/person/{id}", personId)
.retrieve()
.bodyToMono(Person.class)
.onErrorMap((Throwable error) -> error);

onErrorMap will make the Mono to actually throw an error when Zip blocks, terminating zip and letting spring or any other class that you want to handle the exception.

你问的时候不是很清楚

“如何让 zip 方法抛出异常而不返回 null?”

在 webflux 中,您通常不会抛出异常,而是传播异常然后处理它们。 为什么? 因为我们正在处理数据流,如果抛出异常,stream 结束,客户端断开连接,事件链停止。

我们仍然希望维护数据的 stream 并在坏数据流过时对其进行处理。

您可以使用doOnError方法处理错误。

.onStatus(HttpStatus::is4xxClientError, clientResponse ->
         Mono.error(new Data4xxException(String.format(
            "Could not GET data with id: %s from another app, due to error: 
             %s", key, clientResponse))))

Mono.zip( .. ).doOnError( //Handle your error, log or whatever )

如果您想做更具体的事情,您必须使用您希望如何处理错误来更新您的问题。

每当收到状态码为 4xx 或 5xx 的响应时,WebClient 中的 retrieve() 方法就会引发 WebClientResponseException。

与retrieve() 方法不同,exchange() 方法在4xx 或5xx 响应的情况下不会抛出异常。 您需要自己检查状态代码并以您想要的方式处理它们。

   Mono<Object> result = webClient.get().uri(URL).exchange().log().flatMap(entity -> {
        HttpStatus statusCode = entity.statusCode();
        if (statusCode.is4xxClientError() || statusCode.is5xxServerError())
        {
            return Mono.error(new Exception(statusCode.toString()));
        }
        return Mono.just(entity);
    }).flatMap(clientResponse -> clientResponse.bodyToMono(JSONObject.class))

参考: https://www.callicoder.com/spring-5-reactive-webclient-webtestclient-examples/

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM