【问题标题】:How to set and handle timeout in Spring WebClient?如何在 Spring WebClient 中设置和处理超时?
【发布时间】:2019-02-17 12:12:19
【问题描述】:

Spring 文档说需要手动为 WebClient 配置 http 客户端以设置超时:https://docs.spring.io/spring/docs/current/spring-framework-reference/web-reactive.html#webflux-client-builder-reactor-timeout。 但是由于 WebClient 返回响应式 Mono,因此可以(api-wise)应用 .timeout 方法。

效果一样吗?

此外,当使用.timeout 方法时,预计Reactor 的TimeoutException。如果手动完成配置,流中是否会出现相同的错误,即doOnError(TimeoutException.class, ...) 是否有效?

【问题讨论】:

  • 您是否尝试使用 Wiremock 来检查这一点,它会模拟响应时间超过超时的端点?

标签: java spring spring-webflux project-reactor reactive


【解决方案1】:

我的发现

以特定于 http 客户端的方式设置超时将导致特定于 http 客户端的异常,即WebClient 不会包装异常:

@Test
void test() {
    var host = "localhost";
    var endpoint = "/test";
    var port = 8089;
    var timeout = Duration.ofSeconds(3);

    WireMockServer wireMockServer = new WireMockServer(wireMockConfig().port(8089));
    wireMockServer.start();
    WireMock.configureFor(host, wireMockServer.port());

    WireMock.stubFor(get(urlEqualTo(endpoint))
        .willReturn(aResponse().withFixedDelay((int) timeout.toMillis())));

    HttpClient httpClient = HttpClient.create()
        .tcpConfiguration(client ->
            client.doOnConnected(conn -> conn
                .addHandlerLast(new ReadTimeoutHandler((int) (timeout.toSeconds() / 2)))
                .addHandlerLast(new WriteTimeoutHandler((int) (timeout.toSeconds() / 2)))));

    WebClient webClient = WebClient.builder()
        .baseUrl(format("http://%s:%d", host, port))
        .clientConnector(new ReactorClientHttpConnector(httpClient)).build();

    webClient.get().uri(endpoint).retrieve().bodyToMono(Recommendation.class).block();
}

这将导致io.netty.handler.timeout.ReadTimeoutException

.timeout(timeout.dividedBy(2)).block() 会导致常规的TimeoutException (java.util.concurrent),但网络客户端是否会在之后处理连接仍然是一个悬而未决的问题(可能不会)。

我的解决方案是使用 http 客户端特定配置来确保使用连接的本机和正确方式,同时添加新的处理程序,将与 http 客户端相关的异常包装到更通用的异常(或 java.util.concurrent.TimeoutException)中,以便 WebClient 客户端不会取决于提供者例外。

【讨论】:

  • 您将需要这些静态导入: import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;导入静态 com.github.tomakehurst.wiremock.client.WireMock.get;导入静态 com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;导入静态 com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig;
  • 你是如何测试 WriteTimeoutException 的?
猜你喜欢
  • 2018-02-24
  • 2021-08-13
  • 2018-08-06
  • 1970-01-01
  • 2019-11-23
  • 2012-09-01
  • 2018-06-14
  • 2013-12-21
  • 2020-10-12
相关资源
最近更新 更多