Apache HttpClient 抛出 java.net.SocketException:如果我将其用作单例,连接将重置
Apache HttpClient throws java.net.SocketException: Connection reset if I use it as singletone
我创建了一个 Apache HTTP 客户端
CloseableHttpClient client = HttpClients.custom()
.setMaxConnPerRoute(25)
.setMaxConnTotal(50)
.setDefaultRequestConfig(RequestConfig.custom()
.setConnectionRequestTimeout(20_000)
.build())
.build();
我将其用作单例。我有这种发送请求的方法:
public RestResponse sendPost(String serverUrl, String body) throws RestException {
try {
HttpPost httpPost = new HttpPost(serverUrl);
httpPost.setEntity(new StringEntity(body));
try (CloseableHttpResponse response = client.execute(httpPost)) {
RestResponse restResponse = new RestResponse();
restResponse.setCode(response.getStatusLine().getStatusCode());
restResponse.setBody(EntityUtils.toString(response.getEntity()));
return restResponse;
}
} catch (Exception e) {
throw new RestException(e);
}
}
它工作正常。但是在闲置一段时间(5-6 分钟)后,如果我发送请求,我会得到 "java.net.SocketException: Connection reset"
我有 2 个问题
如何找到这个时间开始的地方?这些参数对我不起作用
.setSocketTimeout(25_000)
.setConnectTimeout(26_000)
解决此问题的最佳方法是什么? (我的意思是在每次请求之后或之前重试请求或更改超时或重新连接)
这是经典(阻塞)i/o 的一般限制:阻塞连接在空闲时无法对任何 i/o 事件做出反应(未参与 i/o 操作)。同样,超时设置对空闲连接没有影响。
可以采用多种防御措施来最大程度地减少持久连接重置的可能性:
- 在一段时间不活动后(例如,1 秒后)从连接池租用时验证持久连接
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
cm.setValidateAfterInactivity(1000);
CloseableHttpClient httpclient = HttpClients.custom()
.setConnectionManager(cm)
.build();
- 主动从连接池中驱逐过期连接和空闲超过一定时间(例如5s)的连接
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
cm.setValidateAfterInactivity(1000);
CloseableHttpClient httpclient = HttpClients.custom()
.setConnectionManager(cm)
.evictExpiredConnections()
.evictIdleConnections(5L, TimeUnit.SECONDS)
.build();
- 如果其他一切都失败了,请重试可以安全重试的请求。当需要更多控制时,可能希望使用自定义
HttpRequestRetryHandler
实现而不是默认实现。
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
cm.setValidateAfterInactivity(1000);
CloseableHttpClient httpclient = HttpClients.custom()
.setConnectionManager(cm)
.setRetryHandler(DefaultHttpRequestRetryHandler.INSTANCE)
.build();
- 当预计长时间不活动时,手动从池中逐出连接。这是 HttpClient 在配置
evictIdleConnections
方法时自动为您执行的操作,但需要额外的监视器线程。
cm.closeIdleConnections(0, TimeUnit.MICROSECONDS);
我创建了一个 Apache HTTP 客户端
CloseableHttpClient client = HttpClients.custom()
.setMaxConnPerRoute(25)
.setMaxConnTotal(50)
.setDefaultRequestConfig(RequestConfig.custom()
.setConnectionRequestTimeout(20_000)
.build())
.build();
我将其用作单例。我有这种发送请求的方法:
public RestResponse sendPost(String serverUrl, String body) throws RestException {
try {
HttpPost httpPost = new HttpPost(serverUrl);
httpPost.setEntity(new StringEntity(body));
try (CloseableHttpResponse response = client.execute(httpPost)) {
RestResponse restResponse = new RestResponse();
restResponse.setCode(response.getStatusLine().getStatusCode());
restResponse.setBody(EntityUtils.toString(response.getEntity()));
return restResponse;
}
} catch (Exception e) {
throw new RestException(e);
}
}
它工作正常。但是在闲置一段时间(5-6 分钟)后,如果我发送请求,我会得到 "java.net.SocketException: Connection reset"
我有 2 个问题
如何找到这个时间开始的地方?这些参数对我不起作用
.setSocketTimeout(25_000) .setConnectTimeout(26_000)
解决此问题的最佳方法是什么? (我的意思是在每次请求之后或之前重试请求或更改超时或重新连接)
这是经典(阻塞)i/o 的一般限制:阻塞连接在空闲时无法对任何 i/o 事件做出反应(未参与 i/o 操作)。同样,超时设置对空闲连接没有影响。
可以采用多种防御措施来最大程度地减少持久连接重置的可能性:
- 在一段时间不活动后(例如,1 秒后)从连接池租用时验证持久连接
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
cm.setValidateAfterInactivity(1000);
CloseableHttpClient httpclient = HttpClients.custom()
.setConnectionManager(cm)
.build();
- 主动从连接池中驱逐过期连接和空闲超过一定时间(例如5s)的连接
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
cm.setValidateAfterInactivity(1000);
CloseableHttpClient httpclient = HttpClients.custom()
.setConnectionManager(cm)
.evictExpiredConnections()
.evictIdleConnections(5L, TimeUnit.SECONDS)
.build();
- 如果其他一切都失败了,请重试可以安全重试的请求。当需要更多控制时,可能希望使用自定义
HttpRequestRetryHandler
实现而不是默认实现。
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
cm.setValidateAfterInactivity(1000);
CloseableHttpClient httpclient = HttpClients.custom()
.setConnectionManager(cm)
.setRetryHandler(DefaultHttpRequestRetryHandler.INSTANCE)
.build();
- 当预计长时间不活动时,手动从池中逐出连接。这是 HttpClient 在配置
evictIdleConnections
方法时自动为您执行的操作,但需要额外的监视器线程。
cm.closeIdleConnections(0, TimeUnit.MICROSECONDS);