web-dev-qa-db-ja.com

Spring 5 webflux Webclientでタイムアウトを設定する方法

私は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を設定する方法がわかりません

11
Seb

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())))
12
Artem Bilan

読み取りおよび接続タイムアウトを設定するには、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();
20
joshiste

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()
10
mcoolive

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();
4

これが私がやった方法です(@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();
3
Seb

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();
1
Ivan Krizsan

上記のコメントに基づいて、ソケットタイムアウトを追加する場合は、同じ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();
0
Nishanth Banda