超时设置

由于 Netty 是 Spring WebFlux 的默认客户端库,本文将以为 Reactor Netty HttpClient 为例

响应超时

响应超时是指发送请求后等待接收响应的时间。可以使用 responseTimeout() 方法为客户端配置它:

// 配置超时时间为 1s,Netty 默认不设置响应超时。
HttpClient httpClient = HttpClient.create().responseTimeout(Duration.ofSeconds(1));
WebClient webClient = WebClient.builder().clientConnector(new ReactorClientHttpConnector(httpClient)).build();

连接超时

连接超时是客户端和服务器之间建立链接的必须时间段,可以使用不同的 Channel Option keyoption() 方法来设置。Netty 默认值为 30 秒。

HttpClient httpClient = HttpClient.create().option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 1000);
WebClient webClient = WebClient.builder().clientConnector(new ReactorClientHttpConnector(httpClient)).build();

此外,还可以配置 keep-alive 选项,它可以在连接空闲时发送 TCP 保活探测报文。

HttpClient httpClient = HttpClient.create()
      .option(ChannelOption.SO_KEEPALIVE, true)
      .option(EpollChannelOption.TCP_KEEPIDLE, 300)
      .option(EpollChannelOption.TCP_KEEPINTVL, 60)
      .option(EpollChannelOption.TCP_KEEPCNT, 8);

启用了 keep-alive,在空闲 5 分钟后以 60 秒为间隔进行探测。还将连接中断前的最大探测次数设置为 8 次。

当连接在给定时间内未建立或被放弃时,会抛出 ConnectTimeoutException 异常。

读写超时

读取超时发生在一定时间内没有读取数据,而写入超时发生在写入操作无法在特定时间内完成。 HttpClient 允许配置额外的 Handler 来配置这些超时:

HttpClient client = HttpClient.create()
  .doOnConnected(conn -> conn
    .addHandler(new ReadTimeoutHandler(10, TimeUnit.SECONDS))
    .addHandler(new WriteTimeoutHandler(10)));

通过 doOnConnected() 方法配置连接回调,并在其中添加了 ReadTimeOutHandlerWriteTimeOutHandler 实例处理读写超时,超时时间都设置为 10 秒。

这些 Handler 的构造函数接受两种不同的参数。可以指定 TimeUnit 以及对应的值,或者只指定一个值,默认的单位是秒。

底层的 Netty 库提供了 ReadTimeoutExceptionWriteTimeoutException 异常类来表示对应的超时异常。

SSL/TLS 超时

握手超时是系统在停止操作之前尝试建立 SSL 连接的时间,可以通过 secure() 方法设置 SSL 配置

HttpClient client = HttpClient.create()
        .secure(spec -> spec.sslContext(SslContextBuilder.forClient())
                .defaultConfiguration(SslProvider.DefaultConfigurationType.TCP)
                .handshakeTimeout(Duration.ofSeconds(30))
                .closeNotifyFlushTimeout(Duration.ofSeconds(10))
                .closeNotifyReadTimeout(Duration.ofSeconds(10)));

如上,将握手超时设置为 30 秒(默认值:10 秒),将 close_notify flush(默认值:3 秒)和 read(默认值:0 秒)超时设置为 10 秒。所有方法都由 SslProvider.Builder 接口提供。

当由于超时而导致握手失败时,将抛出 SslHandshakeTimeoutException

代理超时

HttpClient 还支持代理功能。如果与对等端的连接在指定时间内未完成,连接将失败。可以通过 proxy() 设置这个超时时间:

HttpClient httpClient= HttpClient.create()
  .proxy(spec -> spec.type(ProxyProvider.Proxy.HTTP)
    .host("proxy")
    .port(8080)
    .connectTimeoutMillis(30000));

使用 connectTimeoutMillis() 将超时时间设置为 30 秒,默认值为 10 秒。

在连接失败时,Netty 会抛出 ProxyConnectException

请求超时

在上一节中,使用 HttpClient 全局配置了不同的超时。不过,也可以独立于全局设置,设置特定请求响应的超时。

使用 HttpClientRequest 设置响应超时

WebClient webClient= webClient.get()
  .uri("https://baeldung.com/path")
  .httpRequest(httpRequest -> {
    HttpClientRequest reactorRequest = httpRequest.getNativeRequest();
    reactorRequest.responseTimeout(Duration.ofSeconds(2));
  });

如上,使用 WebClienthttpRequest() 方法来访问底层 Netty 库的原生 HttpClientRequest。接着,将超时值设置为 2 秒。

该设置会覆盖 HttpClient 层面的任何响应超时设置。也可以将此值设置为 null,以删除任何先前配置的值。

配置 “响应式流” 超时

Reactor Netty 使用 Reactor Core 作为 Reactive Stream 实现。可以使用 Mono 和 Flux Publisher 提供的 timeout() 方法来配置另一个超时:

WebClient webClient = webClient.get()
  .uri("https://baeldung.com/path")
  .retrieve()
  .bodyToFlux(JsonNode.class)
  .timeout(Duration.ofSeconds(5));

在这种情况下,如果在 5 秒内没有项目到达,就会出现 TimeoutException 异常。

最好使用 Reactor Netty 中提供的更具体的超时配置选项,因为它们能为特定目的和用例提供更多控制。

timeout() 方法适用于整个操作,包括与远程建立连接到接收响应。它不会覆盖任何与 HttpClient 相关的设置。

最后更新于

这有帮助吗?