How to set a timeout in Spring 5 WebFlux WebClient

前端 未结 7 1961
暗喜
暗喜 2020-12-01 06:30

I\'m trying to set timeout on my WebClient, here is the current code :

SslContext sslContext = SslContextBuilder.forClient().trustManager(InsecureTrustManag         


        
相关标签:
7条回答
  • 2020-12-01 07:08

    As Spring Webflux was updated, here is a solution that works for Java (based on the answer for Kotlin):

    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();
    
    0 讨论(0)
  • 2020-12-01 07:09

    Based on the above comment if you want to add a Socket Timeout just add it as another option in the same 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 讨论(0)
  • 2020-12-01 07:15

    The WebFlux WebClient doesn't use Apache Commons HTTP Client. Although you might be able to implement one solution via custom ClientHttpConnector. The existing ReactorClientHttpConnector is based on the Netty. So, consider to use Netty options to configure the client, e.g.:

    ReactorClientHttpConnector connector =
                new ReactorClientHttpConnector(options ->
                        options.option(ChannelOption.SO_TIMEOUT, this.applicationConfig.getHttpClientConnectTimeout()));
    

    or

    .onChannelInit(channel -> channel.config().setConnectTimeoutMillis(this.applicationConfig.getHttpClientConnectTimeout()))
    

    UPDATE

    We also can use ReadTimeoutHandler:

    .onChannelInit(channel -> 
            channel.pipeline()
               .addLast(new ReadTimeoutHandler(this.applicationConfig.getHttpClientConnectTimeout())))
    
    0 讨论(0)
  • 2020-12-01 07:18

    ReactorClientHttpConnector API changed in version Spring WebFlux 5.1.

    So I do the following (Kotlin syntax, based on @joshiste example):

    val tcpClient = TcpClient.create()
        .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 10_000)
        .doOnConnected { connection ->
            connection.addHandlerLast(ReadTimeoutHandler(10))
                .addHandlerLast(WriteTimeoutHandler(10))
        }
    
    val myWebClient = webClientBuilder
        .clientConnector(ReactorClientHttpConnector(HttpClient.from(tcpClient)))
        .baseUrl(myEndPoint)
        .build()
    
    0 讨论(0)
  • 2020-12-01 07:19

    Here's how I did it (thanks to @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();
    
    0 讨论(0)
  • 2020-12-01 07:20

    With Spring Webflux 5.1.8 I ran into problems yielding the error messages below using the answer from mcoolive when executing multiple subsequent tests that uses the WebClient.

    Force-closing a channel whose registration task was not accepted by an event loop
    Failed to submit a listener notification task. Event loop shut down?

    Adding a connection provider and loop resources solved my problem:

    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();
    
    0 讨论(0)
提交回复
热议问题