java - 在一段时间后调用 API 时第一次获取连接重置异常

标签 java spring spring-boot http connection-pooling

我们正在对 API 进行后期调用,当我们在一段时间后开始调用此 API 时(在我们的案例中大部分时间为 10 分钟,如果间隔为 5 分钟,我们很少得到),我们会在第一次尝试时收到连接重置异常,然后其余的即时调用工作正常,但是如果调用此 API 的间隔为 10 分钟,然后再次调用,我们会在该间隔后的第一次调用中得到此类异常。
我们正在使用 Java spring-boot Resttamplate 进行 API 调用并使用 Apache httpclient-4.5.2
apache 日志 "[read] I/O error: Read timed out" Java 日志 Connection reset; nested exception is java.net.SocketException: Connection reset Resttamplate 配置

@Bean
    public RestTemplate restTemplate() {
        RestTemplate restTemplate = new RestTemplate(clientHttpRequestFactory());
        return restTemplate;
    }

@Bean
    public HttpComponentsClientHttpRequestFactory clientHttpRequestFactory() {
        HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory();
        clientHttpRequestFactory.setHttpClient(httpClient());
        return clientHttpRequestFactory;
    }

@Bean
    public CloseableHttpClient httpClient() {
        RequestConfig requestConfig = RequestConfig.custom()
            .setConnectionRequestTimeout(180000)
            .setConnectTimeout(180000)
            .setSocketTimeout(180000).build();

        return HttpClients.custom()
            .setDefaultRequestConfig(requestConfig)
            .setConnectionManager(poolingConnectionManager())
           // .setKeepAliveStrategy(connectionKeepAliveStrategy())
            .build();
    }

@Bean
    public PoolingHttpClientConnectionManager poolingConnectionManager() {
        PoolingHttpClientConnectionManager poolingConnectionManager = new PoolingHttpClientConnectionManager();
        poolingConnectionManager.setMaxTotal(50);
        return poolingConnectionManager;
    }
如果我们在 HttpClients.custom() 中添加 set connectionKeepAliveStrategy 如下所述,我们将不会遇到任何此类异常。
@Bean
    public ConnectionKeepAliveStrategy connectionKeepAliveStrategy() {
        return new ConnectionKeepAliveStrategy() {
            @Override
            public long getKeepAliveDuration(HttpResponse response, HttpContext context) {
                HeaderElementIterator it = new BasicHeaderElementIterator
                    (response.headerIterator(HTTP.CONN_KEEP_ALIVE));
                while (it.hasNext()) {
                    HeaderElement he = it.nextElement();
                    String param = he.getName();
                    String value = he.getValue();

                    if (value != null && param.equalsIgnoreCase("timeout")) {
                        return Long.parseLong(value) * 1000;
                    }
                }
                return 20000;
            }
        };
    }
不知道为什么这种异常会随着 connectionKeepAliveStrategy 消失。它在这当中起什么作用?
提前致谢。

最佳答案

查询 these两个重要的点:
栏目 2.6 - 连接保持 Activity 策略 :

  • Keep-Alive响应中的 header

  • If the Keep-Alive header is not present in the response, HttpClient assumes the connection can be kept alive indefinitely.


    我猜有一个 Keep-Alive api 响应中的 header ,值为 600 秒。
  • 定制 keep-alive策略:

  • However, many HTTP servers in general use are configured to drop persistent connections after a certain period of inactivity in order to conserve system resources, quite often without informing the client. In case the default strategy turns out to be too optimistic, one may want to provide a custom keep-alive strategy.

    关于java - 在一段时间后调用 API 时第一次获取连接重置异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62552480/

    相关文章:

    java - spring中相对路径文件导入的起始路径是什么

    java - Spring Boot 中的 @ComponentScan 和 @EnableAutoConfiguration 有什么区别?

    java - Spring boot 找不到 PropertySource : label not found

    java - ant 可运行 jar 不工作

    java - 我正确使用 list.remove 吗?

    java - 如何执行我的 java 桌面应用程序的单个实例?

    java - 将Entity类转换为很多DTO

    Spring Boot Actuator 'http.server.requests' 公制 MAX 时间

    java - 如何在 PDFBOX 中用 URL 替换字符串?

    java - 使用 EntityManagerFactory 时遇到问题