当前位置: 首页 > 知识库问答 >
问题:

如何使用Apache HttpClient获得持久的HttpConnection?

太叔鸿
2023-03-14

在我的测试应用程序中,我使用Apache HttpClient向同一主机执行连续的HttpGet请求,但在每个下一个请求时,都会发现之前的HttpConnection被关闭并创建新的HttpConnection。

我使用同一个HttpClient实例,不关闭响应。我从每个实体获取InputStream,用扫描仪读取,然后关闭扫描仪。我测试了KeepAlivestStrategy,结果是真的。请求之间的时间间隔不超过keepAlive或ConnectionTimeOlive持续时间。

谁能告诉我这种行为的原因是什么?

已更新

我找到了解决方案。为了保持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操作的执行。如果托管连接被其使用者释放或显式关闭,则基础连接将与其代理分离并返回给管理器。即使服务消耗er仍然持有对代理实例的引用,它不再能够执行任何I/O操作,或者有意或无意地更改实际连接的状态。“(HttpClent教程

正如@oleg所指出的,跟踪连接的正确方法是使用记录器。

共有3个答案

关项明
2023-03-14

从HttpClient网站上的示例:

// 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所说,您需要在检查连接状态之前关闭HttpACK。

融烨磊
2023-03-14

您的应用程序必须关闭响应对象,以确保基础连接的适当资源分配。响应关闭后,HttpClient将有效连接保持活动状态,并将其返回到连接管理器(连接池)。

我怀疑您的代码只是泄漏了连接,并且每个请求都会产生一个新创建的连接,而所有以前的连接都会继续在内存中堆积。

滑畅
2023-03-14

首先,您需要确保正在使用的远程服务器支持保持活动连接。只需检查远程服务器是否在每个响应中返回头Connection:Keep AliveConnection:Closed。对于关闭案例,您对此无能为力。您可以使用此在线工具执行此类检查。

接下来,您需要实施本手册第#2.6段中定义的连接KeepAlivestStrategy。请注意,自HttpClient 4.0版以来,您可以使用现有的DefaultConnectionKeepAliveStrategy,这样您的HttpClient将按照以下方式构造:

HttpClient client = HttpClients.custom()
    .setKeepAliveStrategy(DefaultConnectionKeepAliveStrategy.INSTANCE)
    .build();

如果服务器支持,这将确保您的HttpClient实例将通过保持活动机制重用相同的连接。

 类似资料:
  • 问题内容: 您好,我对hibernate世界非常陌生,似乎遇到了障碍。我需要存储的对象中有一个哈希映射。 事情是,我永远不需要使用此映射进行搜索,排序或做任何事情,我只需要将其与对象一起保存并在加载对象时加载它,因此我希望hibernate可以通过某种方式对其进行序列化然后将其存储在CLOB或BLOB字段中,但是我似乎找不到任何方法。 所以我接下来试图让hibernate保存这样 但这在运行时给了

  • 问题内容: 我想知道如何禁用Redis的持久性。这里提到了这样做的可能性:http : //redis.io/topics/persistence。我的意思是和那里描述的完全一样。任何帮助将不胜感激! 问题答案: 要禁用Redis中的 所有 数据持久性,请执行以下操作: 通过将配置指令设置为(默认值)来禁用AOF 通过禁用(注释掉)所有配置指令来禁用RDB快照(默认情况下定义了3个) 这些配置指令

  • 我在想如何禁用Redis的耐药性。这里提到了这样做的可能性:http://redis.io/topics/persistence。我的意思和那里描述的完全一样。任何帮助都将非常感谢!

  • 问题内容: 我正在寻找一种聪明且易于理解的方法来使用获取持久化实体的ID 。ID是。 可以想到以下解决方案: 没有使用策略。这要求在保留之前先查找一个免费的id,然后将其放入要保留的实体中:麻烦,但可以。 有策略。持久性提供程序将负责生成id。这看起来更聪明,但是如何获取ID? 请参阅下面的解决方案2 这会显示一个空ID! 有什么建议?我正在使用MySql,EclipseLink,但需要一个可移植

  • 我在云上保存了一个持久的锚(365天)。现在,我想找回它。我可以很好地使用谷歌在其示例项目之一中提供的代码。然而,我想使用场景形式,因为我想在之后做一些操作(绘制3D形状),这在场景形式中更容易做到。然而,我似乎无法解决持续的云锚。我在网上找到的所有例子,都不处理持久的云锚,它们只处理正常的24小时云锚。 我写的上面的更新函数有什么错误吗?CloudAnchorManager类与Google在其持

  • 据我所知,Room不允许您在主线程上发出数据库查询(这可能会导致主线程上的延迟)。想象一下,我正试图在UI主线程上更新一个textview,其中包含一些数据,我将如何获得回拨。让我给你举个例子。假设我想将业务模型数据存储到一个名为Events的对象中。因此,我们将有一个EventDao对象: 想象我们在下面有这个DAO对象: 现在在一些活动中,我有一个文本视图,我想更新它的值,所以我这样做: 因为