在 Spring WebFlux Webclient 中设置超时

我正在使用Spring Webflux WebClient从我的Spring引导应用程序进行REST调用。每次在30秒内获得超时。

以下是我试图在WebClient of Spring webfulx中设置套接字超时的一些代码。

 - ReactorClientHttpConnector connector = new ReactorClientHttpConnector(options -> options
           .option(ChannelOption.SO_TIMEOUT, 600000).option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 600000));
 - ReactorClientHttpConnector connector = new ReactorClientHttpConnector(
           options -> options.afterChannelInit(chan -> {
                chan.pipeline().addLast(new ReadTimeoutHandler(600000));
            }));
 - ReactorClientHttpConnector connector1 = new ReactorClientHttpConnector(options -> options
            .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 600000).afterNettyContextInit(ctx -> {
                ctx.addHandlerLast(new ReadTimeoutHandler(600000, TimeUnit.MILLISECONDS));
            }));

并尝试使用“clientConnector”方法在“WebClient”中添加上述连接器设置。

并且还尝试设置超时,如下所示:

webClient.get().uri(builder -> builder.path("/result/{name}/sets")
                    .queryParam("q", "kind:RECORDS")
                    .queryParam("offset", offset)
                    .queryParam("limit", RECORD_COUNT_LIMIT)
                    .build(name))
            .header(HttpHeaders.AUTHORIZATION, accessToken)
            .exchange().timeout(Duration.ofMillis(600000))
            .flatMap(response -> handleResponse(response, name, offset));

上述选项都不适合我。

我正在使用 org.springframework.boot:spring-boot-gradle-plugin:2.0.0.M7,它之间依赖于 org.springframework:spring-webflux:5.0.2.RELEASE。

请在这里建议,让我知道,如果我在这里做错了什么。


答案 1

我已尝试重现该问题,但无法做到。使用反应器网 0.7.5.RELEASE。

我不确定你说的是哪个超时。

可以使用 配置连接超时。我在“正在连接”日志消息和实际错误之间有10秒钟:ChannelOption.CONNECT_TIMEOUT_MILLIS

WebClient webClient = WebClient.builder()
    .clientConnector(new ReactorClientHttpConnector(options -> options
        .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 10000)))
    .build();

webClient.get().uri("http://10.0.0.1/resource").exchange()
    .doOnSubscribe(subscription -> logger.info("connecting"))
    .then()
    .doOnError(err -> logger.severe(err.getMessage()))
    .block();

如果您正在谈论读/写超时,那么您可以查看Netty和.ReadTimeoutHandlerWriteTimeoutHandler

一个完整的示例可能如下所示:

ReactorClientHttpConnector connector = new ReactorClientHttpConnector(options ->
        options.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 10)
                .onChannelInit(channel -> {
                        channel.pipeline().addLast(new ReadTimeoutHandler(10))
                                .addLast(new WriteTimeoutHandler(10));
                return true;
        }).build());

从 Reactor Netty 0.8 和 Spring Framework 5.1 开始,配置现在如下所示:

TcpClient tcpClient = TcpClient.create()
                 .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 1000)
                 .doOnConnected(connection ->
                         connection.addHandlerLast(new ReadTimeoutHandler(10))
                                   .addHandlerLast(new WriteTimeoutHandler(10)));
WebClient webClient = WebClient.builder()
    .clientConnector(new ReactorClientHttpConnector(HttpClient.from(tcpClient)))
    .build();

也许将以下内容添加到您的内容中将提供有关HTTP级别所发生情况的更多信息:application.properties

logging.level.reactor.ipc.netty.channel.ContextHandler=debug
logging.level.reactor.ipc.netty.http.client.HttpClient=debug

答案 2

因为现在在最新的 netty 中已弃用(v0.9.x,并将在 v1.1.0 中删除)。您可以使用和忽略在其他代码中看到的过多 HTTP 连接配置,并且此实现适用于旧版本和新版本。HttpClient.from(tcpClient)responseTimeout()

创建 HttpClient

HttpClient httpClient = HttpClient.create().responseTimeout(Duration.ofMillis(500)); // 500 -> timeout in millis

使用 webClient builder fxn 将 httpClient 添加到 webclient.clientConnector()

WebClient
.builder()
.baseUrl("http://myawesomeurl.com")
.clientConnector(new ReactorClientHttpConnector(httpClient))
.build();

此外,网站上提供的大多数实现都不会被弃用,以确保您没有使用已弃用的实现,您可以查看此链接

仅供参考:对于较旧的netty版本(即< v0.9.11版本)在引擎盖下使用tcpConfiguration(),这在新版本中已弃用。但是reactTimeout()在>=v0.9.11中使用了新的实现,所以即使你将来更改项目的netty版本,你的代码也不会中断。responseTimeout()

注意:如果您使用的是旧的netty版本,该版本有时默认带有spring,则可能也可以使用Brian的实现。(虽然不确定)

如果你想阅读更多关于reactTimeout()及其工作原理的信息,你可以在这里这里查看源代码,或者在这里检查github gist。


推荐