异步 WebClient 请求的异常处理

Exception Handling for async WebClient request

最近我一直在使用WebClient。我正在创建同步请求和异步请求。在同步请求中,我能够捕获 WebClientResponseException 而当我尝试在异步请求中捕获 WebClientResponseException (也尝试使用通用异常,但没有用)时,它无法被捕获。我在互联网上找不到任何示例。我不确定在异步 WebClient 请求中是否可以进行此类异常处理。

以下是代码示例:

Sync Request(可以捕获异常的地方)

{
webClient
.post()
.uri(POST_ENDPOINT)
.bodyValue(cloudEvent)
.header("Authorization", token)
.retrieve()
.toEntity(String.class)
.block();
 
}
catch(final WebClientResponseException e)
{
log.error(String.valueOf(e));
throw new MyCustomException ("");
} 

Async Request(无法捕获异常的地方)

try
{
stream=
webClient
.get()
.uri(GET_ENDPOINT)
.header("Authorization", token)
.retrieve()
.bodyToFlux(Any_Parametrized_Type_Reference);
}
catch(ffinal WebClientResponseException e)
{
log.error(String.valueOf(e));
throw new MyCustomException ("");
}

提前感谢您的回复。

Async表示进程会被转移到另一个线程。 bodyToFlux 将执行此操作并完成执行,但您对该线程没有任何控制权,因为在您当前的线程中,该函数已执行并且不会触发问题。

这类似于 JS 中的 Promises,您应该在任何异常情况下进行回调。

在 bodyToFlux 之后,您可以添加这些回调。

webClient.get()
  .uri("https://baeldung.com/path")
  .retrieve()
  .bodyToFlux(JsonNode.class)
  .timeout(Duration.ofSeconds(5))
  .onErrorMap(ReadTimeoutException.class, ex -> new HttpTimeoutException("ReadTimeout"))
  .onErrorReturn(SslHandshakeTimeoutException.class, new TextNode("SslHandshakeTimeout"))
  .doOnError(WriteTimeoutException.class, ex -> log.error("WriteTimeout"))

onErrorMap、onErrorReturn 和 doOnError 收到您的回调并在出现异常时执行 lambda 方法。

更多信息在这里:https://www.baeldung.com/spring-webflux-timeout#exception-handling

感谢@CarlosCárdenas;当我在本地测试时,以下更改对我有用。

private static final Function<WebClientRequestException, MyCustomException>
    EXCEPTION_MAPPER =
        ex ->
            new MyCustomException(ex.getCause());

    webClient
        .get()
        .uri(GET_ENDPOINT)
        .header("Authorization", token)
        .retrieve()
        .bodyToFlux(Any_Parametrized_Type_Reference)
        .onErrorMap(WebClientRequestException.class, EXCEPTION_MAPPER)
        .doOnError(MyCustomException.class, ex -> myExceptionHandlingMethod(ex)); 

目前,我遇到了相关单元测试的问题。它不应该抛出异常,所以我无法捕获异常。我想我遗漏了一些关于测试异步流程的内容。我的测试看起来像这样:

@Test
void myTest() 
{
  
// Given
…

//When
  final Executable executeMyMethod=
      () -> myMethod(parameter1, parameter2);

  // Then
 // await().pollDelay(Duration.FIVE_SECONDS).untilAsserted(() -> assertTrue(true)); -> I’m not sure if it is needed or not
  assertThrows(MyCustomException.class, executeMyMethod);
}