在我的测试应用程序中,我使用 Apache HttpClient 对同一主机执行连续的HttpGet请求,但是在每次下一个请求时都会发现前一个HttpConnection已关闭且新的HttpConnection已创建。
我使用相同的HttpClient实例并且不要关闭响应。我从每个实体获取InputStream,使用Scanner从中读取,然后关闭Scanner。我测试了KeepAliveStrategy,它返回true。请求之间的时间不超过keepAlive或connectionTimeToLive持续时间。
谁能告诉我这种行为可能是什么原因?
更新
我找到了解决方案。为了使HttpConnecton保持活动状态,在构建HttpClient时需要设置 HttpClientConnectionManager 。我使用了 BasicHttpClientConnectionManager 。
ConnectionKeepAliveStrategy keepAliveStrat = new DefaultConnectionKeepAliveStrategy() {
@Override
public long getKeepAliveDuration(HttpResponse response, HttpContext context)
{
long keepAlive = super.getKeepAliveDuration(response, context);
if (keepAlive == -1)
keepAlive = 120000;
return keepAlive;
}
};
HttpClientConnectionManager connectionManager = new BasicHttpClientConnectionManager();
try (CloseableHttpClient httpClient = HttpClients.custom()
.setConnectionManager(connectionManager) // without this setting connection is not kept alive
.setDefaultCookieStore(store)
.setKeepAliveStrategy(keepAliveStrat)
.setConnectionTimeToLive(120, TimeUnit.SECONDS)
.setUserAgent(USER_AGENT)
.build())
{
HttpClientContext context = new HttpClientContext();
RequestConfig config = RequestConfig.custom()
.setCookieSpec(CookieSpecs.DEFAULT)
.setSocketTimeout(10000)
.setConnectTimeout(10000)
.build();
context.setRequestConfig(config);
HttpGet httpGet = new HttpGet(uri);
CloseableHttpResponse response = httpClient.execute(httpGet, context);
HttpConnection conn = context.getConnection();
HttpEntity entity = response.getEntity();
try (Scanner in = new Scanner(entity.getContent(), ENC))
{
// do something
}
System.out.println("open=" + conn.isOpen()); // now open=true
HttpGet httpGet2 = new HttpGet(uri2); // on the same host with other path
// and so on
}
更新2
通常,检查与conn.isOpen()
的连接不是检查连接状态的正确方法,因为:"内部HTTP连接管理器使用ManagedHttpClientConnection实例作为管理实际连接的代理连接状态并控制I / O操作的执行。如果托管连接被释放或由其使用者显式关闭,则底层连接将从其代理中分离并返回给管理器。 即使服务使用者仍然拥有对代理实例的引用,它也无法有意或无意地执行任何I / O操作或更改实际连接的状态。" (HttpClent Tutorial)
正如@oleg所指出的,跟踪连接的正确方法是使用logger。
答案 0 :(得分:3)
首先,您需要确保您正在使用的远程服务器支持保持活动连接。只需检查远程服务器是否在每个响应中都返回标头Connection: Keep-Alive
或Connection: Closed
。对于Close
案例there is nothing,你可以做到这一点。您可以使用this online tool执行此类检查。
接下来,您需要实现this manual第2.6段中定义的ConnectionKeepAliveStrategy
。请注意,您可以使用现有的DefaultConnectionKeepAliveStrategy
since HttpClient version 4.0,以便将HttpClient
构建如下:
HttpClient client = HttpClients.custom()
.setKeepAliveStrategy(DefaultConnectionKeepAliveStrategy.INSTANCE)
.build();
这将确保您HttpClient
实例将通过保持活动机制重用相同的连接(如果服务器支持它)。
答案 1 :(得分:0)
您的应用程序必须关闭响应对象,以确保正确的资源取消分配底层连接。在响应关闭时,HttpClient保持有效连接处于活动状态并将它们返回给连接管理器(连接池)。
我怀疑你的代码只是泄漏了连接,并且每个请求都依赖于新创建的连接,而所有先前的连接都在堆积在内存中。
答案 2 :(得分:0)
来自HttpClient website的示例:
// In order to ensure correct deallocation of system resources
// the user MUST call CloseableHttpResponse#close() from a finally clause.
// Please note that if response content is not fully consumed the underlying
// connection cannot be safely re-used and will be shut down and discarded
// by the connection manager.
因为@oleg说你需要在检查连接状态之前关闭HttpResponse。