在我的测试应用程序中,我使用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

最佳答案

首先,您需要确保正在使用的远程服务器支持保持活动连接。只需简单地检查远程服务器是否在每个响应中都返回标头Connection: Keep-AliveConnection: 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实例将通过保持活动机制重用相同的连接。

关于java - 如何使用Apache HttpClient获得持久的HttpConnection?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/46053067/

10-12 00:38
查看更多