【问题标题】:Default httpclient for resttemplate, have absolute value for read timeoutresttemplate 的默认 httpclient,具有读取超时的绝对值
【发布时间】:2020-09-07 22:25:44
【问题描述】:

我遇到一个问题,即应用程序在使用 Spring Boot 中的 RestTemplate 进行的 post call 时会无限期阻塞。

ResponseEntity<String> response = restTemplate.postForEntity(destination.getUri(), request, String.class);

我们使用默认的标准 JDK 实现并像这样创建它:

    this.restTemplate = restTemplateBuilder
                       .setConnectTimeout(5000)
                       .setReadTimeout(5000)
                       .build();

这会将连接和读取超时设置为 5 秒。但这似乎不是一个绝对值,一旦我们的应用程序接收到一些字节,这个读取超时就会重置,这会导致我们的应用程序无限期地等待。

我宁愿设置一个绝对读取超时,如果您在不到 5 秒内没有得到结束响应,模板会抛出一个 TimeoutException

我在默认客户端的选项中找不到类似的东西?

---编辑---

我尝试了@Peekay 的答案,但它似乎不起作用:

    CloseableHttpClient httpClient = HttpClientBuilder.create()
           .setConnectionTimeToLive(1, TimeUnit.SECONDS)
           .setConnectionManager(new PoolingHttpClientConnectionManager())
           .build();

   HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory();
   clientHttpRequestFactory.setHttpClient(httpClient);
   return new RestTemplate(clientHttpRequestFactory);

我还尝试了客户端 RestTemplate 的不同实现,例如HttpComponentsClientHttpNetty4ClientOkHttp3Client 像这样创建它们:

    Netty4ClientHttpRequestFactory factory = new Netty4ClientHttpRequestFactory();
    factory.setConnectTimeout(timeout);
    factory.setReadTimeout(readTimeout);
    return new RestTemplate(factory);

并在响应时间超过 5 秒的情况下对它们进行了测试。除了返回 ReadTimeoutException 的 Netty 之外,所有这些都返回了 200 成功。不幸的是,我无法切换到该客户端,如果您想继续使用默认客户端,您似乎需要自己实现它。

【问题讨论】:

    标签: java spring spring-boot


    【解决方案1】:

    你是对的,你不能设置绝对值,你必须中断胎面本身。

    【讨论】:

      【解决方案2】:

      我们解决此问题的方法是将 RestTemplate REST 调用包装在 CompletableFuture 中,并使用该包装器中的超时功能来终止线程(如果耗时过长)。

      这是一个例子:

      CompletableFuture<T> requestWrapper = CompletableFuture.supplyAsync(() -> {
        return restTemplate.postForEntity(/* Whatever arguments you need to pass */);
      });
      
      try {
        return requestWrapper.get(5000, TimeUnit.MILLISECONDS);
      } catch (TimeoutException e) {
        requestWrapper.cancel(true);
        throw new TimeoutException("Endpoint took too long to respond, TimeoutException is triggered");
      } catch (ExecutionException e) {
        throw e.getCause();
      }
      

      【讨论】:

        【解决方案3】:

        您可以使用带有 RestTemplate 的备用 http 客户端,例如 Apache HttpClient,它可以让您更好地控制连接的设置、池化和维护方式:

        • 您可以从其HttpClientBuilder 设置连接生存时间,这是连接的最大 TTL
        • 您可以定义一个RequestConfig 指定一个连接超时(等待建立连接的最长时间)和一个单独的套接字超时(最大时间读取() 将等待数据)。

        更多详情见:setConnectTimeout vs. setConnectionTimeToLive vs. setSocketTimeout()

        【讨论】:

          【解决方案4】:
          -Dsun.net.client.defaultConnectTimeout=<TimeoutInMiliSec>
          -Dsun.net.client.defaultReadTimeout=<TimeoutInMiliSec>
          

          https://howtodoinjava.com/spring-boot2/resttemplate/resttemplate-timeout-example/

          【讨论】:

            猜你喜欢
            • 2012-07-17
            • 2021-07-11
            • 2014-10-23
            • 2020-12-20
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-10-21
            相关资源
            最近更新 更多