首页 > 解决方案 > 如何在 Spring WebClient 中设置和处理超时?

问题描述

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

它有同样的效果吗?

此外,当一个人使用方法时,预计会使用.timeoutReactor 。TimeoutException如果手动完成配置,流中是否会出现相同的错误,即会doOnError(TimeoutException.class, ...)起作用吗?

标签: javaspringspring-webfluxproject-reactorreactive

解决方案


我的发现

以特定于 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() leads to regular TimeoutException (java.util.concurrent) but it's still an open question whether a web client takes care about connections afterwards (probably not).

My solution is to use http client specific configuration to ensure native and correct way to utilize connections while adding new handler that wraps http client related exception into more generic ones (or java.util.concurrent.TimeoutException) so that WebClient clients won't depend on provider exceptions.


推荐阅读