私はWebClientにタイムアウトを設定しようとしています、現在のコードは次のとおりです:
SslContext sslContext = SslContextBuilder.forClient().trustManager(InsecureTrustManagerFactory.INSTANCE).build();
ClientHttpConnector httpConnector = new ReactorClientHttpConnector(opt -> {
opt.sslContext(sslContext);
HttpClientOptions option = HttpClientOptions.builder().build();
opt.from(option);
});
return WebClient.builder().clientConnector(httpConnector).defaultHeader("Authorization", xxxx)
.baseUrl(this.opusConfig.getBaseURL()).build();
私はタイムアウトとプーリング戦略を追加する必要があります、私はそのような何かを考えていました:
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
cm.setMaxTotal(this.applicationConfig.getHttpClientMaxPoolSize());
cm.setDefaultMaxPerRoute(this.applicationConfig.getHttpClientMaxPoolSize());
cm.closeIdleConnections(this.applicationConfig.getServerIdleTimeout(), TimeUnit.MILLISECONDS);
RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(this.applicationConfig.getHttpClientSocketTimeout())
.setConnectTimeout(this.applicationConfig.getHttpClientConnectTimeout())
.setConnectionRequestTimeout(this.applicationConfig.getHttpClientRequestTimeout()).build();
CloseableHttpClient httpClient = HttpClients.custom().setDefaultRequestConfig(requestConfig).setConnectionManager(cm).build();
しかし、WebクライアントでhttpClientを設定する方法がわかりません
WebFlux WebClient
は、Apache Commons HTTP Clientを使用しません。ただし、カスタムClientHttpConnector
を使用して1つのソリューションを実装できる場合があります。既存のReactorClientHttpConnector
はNettyに基づいています。したがって、Nettyオプションを使用してクライアントを構成することを検討してください。例:
ReactorClientHttpConnector connector =
new ReactorClientHttpConnector(options ->
options.option(ChannelOption.SO_TIMEOUT, this.applicationConfig.getHttpClientConnectTimeout()));
または
.onChannelInit(channel -> channel.config().setConnectTimeoutMillis(this.applicationConfig.getHttpClientConnectTimeout()))
[〜#〜] update [〜#〜]
ReadTimeoutHandler
も使用できます。
.onChannelInit(channel ->
channel.pipeline()
.addLast(new ReadTimeoutHandler(this.applicationConfig.getHttpClientConnectTimeout())))
読み取りおよび接続タイムアウトを設定するには、SO_TIMEOUTオプションがNIOを使用するチャネルで使用できないため(および警告Unknown channel option 'SO_TIMEOUT' for channel '[id: 0xa716fcb2]'
)
ReactorClientHttpConnector connector = new ReactorClientHttpConnector(
options -> options.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 2000)
.compression(true)
.afterNettyContextInit(ctx -> {
ctx.addHandlerLast(new ReadTimeoutHandler(5000, TimeUnit.MILLISECONDS));
}));
return WebClient.builder()
.clientConnector(connector)
.build();
ReactorClientHttpConnector APIのバージョンが変更されました Spring WebFlux 5.1 。
そこで、次のことを行います(@joshisteの例に基づいたKotlin構文):
val tcpClient = TcpClient.create()
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 10_000)
.doOnConnected { connection ->
connection.addHandlerLast(ReadTimeoutHandler(10))
.addHandlerLast(WriteTimeoutHandler(10))
}
val myWebClient = WebClient.builder()
.clientConnector(ReactorClientHttpConnector(HttpClient.from(tcpClient)))
.baseUrl(myEndPoint)
.build()
Spring Webfluxが更新されたとき、Java(Kotlinの answer に基づく)に有効なソリューションを次に示します。
TcpClient timeoutClient = TcpClient.create()
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, SECONDS*1000)
.doOnConnected(
c -> c.addHandlerLast(new ReadTimeoutHandler(SECONDS))
.addHandlerLast(new WriteTimeoutHandler(SECONDS)));
return webClientBuilder.baseUrl(YOUR_URL)
.clientConnector(new ReactorClientHttpConnector(HttpClient.from(timeoutClient)))
.build();
これが私がやった方法です(@Artemに感謝)
SslContext sslContext = SslContextBuilder.forClient().trustManager(InsecureTrustManagerFactory.INSTANCE).build();
ClientHttpConnector httpConnector = new ReactorClientHttpConnector(options -> {
options.sslContext(sslContext);
options.option(ChannelOption.SO_TIMEOUT, this.applicationConfig.getHttpClientRequestTimeout());
options.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, this.applicationConfig.getHttpClientConnectTimeout());
options.poolResources(PoolResources.fixed("myPool", this.applicationConfig.getHttpClientMaxPoolSize()));
});
return WebClient.builder().clientConnector(httpConnector).defaultHeader("Authorization", "xxxx")
.baseUrl(this.config.getBaseURL()).build();
Spring Webflux 5.1.8では、WebClient
を使用する複数の後続のテストを実行するときに mcoolive からの回答を使用して、以下のエラーメッセージを生成する問題に遭遇しました。
登録タスクがイベントループで受け入れられなかったチャネルを強制的に閉じる
リスナー通知タスクの送信に失敗しました。イベントループがシャットダウンしましたか?
接続プロバイダーとループリソースを追加すると、問題が解決しました。
final ConnectionProvider theTcpClientPool = ConnectionProvider.elastic("tcp-client-pool");
final LoopResources theTcpClientLoopResources = LoopResources.create("tcp-client-loop");
final TcpClient theTcpClient = TcpClient
.create(theTcpClientPool)
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000)
.runOn(theTcpClientLoopResources)
.doOnConnected(theConnection -> {
theConnection.addHandlerLast(new ReadTimeoutHandler(mTimeoutInMillisec, TimeUnit.MILLISECONDS));
theConnection.addHandlerLast(new WriteTimeoutHandler(mTimeoutInMillisec, TimeUnit.MILLISECONDS));
});
WebClient theWebClient = WebClient.builder()
.baseUrl(mVfwsServerBaseUrl)
.clientConnector(new ReactorClientHttpConnector(HttpClient.from(theTcpClient)))
.build();
上記のコメントに基づいて、ソケットタイムアウトを追加する場合は、同じtimeoutClientの別のオプションとして追加します。
TcpClient timeoutClient = TcpClient.create()
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, SECONDS*10) //Connect Timeout
.option(ChannelOption.SO_TIMEOUT,1000) // Socket Timeout
.doOnConnected(
c -> c.addHandlerLast(new ReadTimeoutHandler(SECONDS))
.addHandlerLast(new WriteTimeoutHandler(SECONDS)));
return webClientBuilder.baseUrl(YOUR_URL)
.clientConnector(new ReactorClientHttpConnector(HttpClient.from(timeoutClient)))
.build();