如何在 Spring WebClient 中设置和处理超时? [英] How to set and handle timeout in Spring WebClient?

查看:340
本文介绍了如何在 Spring WebClient 中设置和处理超时?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Spring docs says it is required to configure http client for WebClient manually to set timeouts: https://docs.spring.io/spring/docs/current/spring-framework-reference/web-reactive.html#webflux-client-builder-reactor-timeout. But since WebClient returns reactive Mono, it's possible (api-wise) to apply .timeout method.

效果一样吗?

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

Moreover, when one uses .timeout method, Reactor's TimeoutException is expected. Will the same error appear in the stream if configuration is done manually i.e. will doOnError(TimeoutException.class, ...) work?

推荐答案

我的发现

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

Setting a timeout in a http client specific way will lead to http client specific exception i.e. WebClient doesn't wrap exceptions:

@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) 但是Web 客户端是否会在之后处理连接(可能不会)仍然是一个悬而未决的问题.

.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).

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

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.

这篇关于如何在 Spring WebClient 中设置和处理超时?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆