HttpClient 4.0.1 – 如何释放连接?

我有一个循环了一堆的URL,每一个我正在做以下几点:

private String doQuery(String url) { HttpGet httpGet = new HttpGet(url); setDefaultHeaders(httpGet); // static method HttpResponse response = httpClient.execute(httpGet); // httpClient instantiated in constructor int rc = response.getStatusLine().getStatusCode(); if (rc != 200) { // some stuff... return; } HttpEntity entity = response.getEntity(); if (entity == null) { // some stuff... return; } // process the entity, get input stream etc } 

第一个查询是好的,第二个引发这个exception:

线程“main”中的exceptionjava.lang.IllegalStateException:SingleClientConnManager的无效使用:连接仍然分配。 确保在分配另一个之前释放连接。 org.apache.http.impl.conn.SingleClientConnManager.getConnection(SingleClientConnManager.java:199)at org.apache.http.impl.conn.SingleClientConnManager $ 1.getConnection(SingleClientConnManager.java:173)……

这只是一个简单的单线程应用程序。 我怎样才能释放这个连接?

Httpcomponents 4.1推荐的方法是closures连接并释放任何底层资源:

 EntityUtils.consume(HttpEntity) 

HttpEntity传递的是响应实体。

这似乎很好:

  if( response.getEntity() != null ) { response.getEntity().consumeContent(); }//if 

即使您没有打开其内容,也不要忘记使用该实体。 例如,你期望从响应中得到一个HTTP_OK状态,但是不要得到它,你仍然需要使用这个实体!

为了回答我自己的问题:释放连接(以及与请求相关的任何其他资源),您必须closures由HttpEntity返回的InputStream:

 InputStream is = entity.getContent(); .... process the input stream .... is.close(); // releases all resources 

从文档

从版本4.2开始,他们引入了一个简化连接发布的简便方法: HttpRequestBase.releaseConnection()

我打算详细解答Apache HttpClient 4.0.1。 我正在使用这个HttpClient版本,因为它是由WAS v8.0提供的,我需要使用在Apache Wink V1.1.1中提供的HttpClient,也是由WAS v8.0提供的,以便对Sharepoint进行一些经NTLMvalidation的REST调用。

引用Apache HttpClient邮件列表中的Oleg Kalnichevski:

几乎所有这些代码是没有必要的。 (1)只要实体内容被消耗到stream的末尾,HttpClient就会自动释放底层连接; (2)在读取响应内容的同时,HttpClient会自动释放底层连接对抛出的任何I / Oexception。 如情况下不需要特殊处理。

事实上,这足以确保正确的资源释放:

 HttpResponse rsp = httpclient.execute(target, req); HttpEntity entity = rsp.getEntity(); if (entity != null) { InputStream instream = entity.getContent(); try { // process content } finally { instream.close(); // entity.consumeContent() would also do } } 

这就对了。

资源

如果不应该使用响应,则可以使用以下代码中止请求:

 // Low level resources should be released before initiating a new request HttpEntity entity = response.getEntity(); if (entity != null) { // Do not need the rest httpPost.abort(); } 

参考: http : //hc.apache.org/httpcomponents-client-ga/tutorial/html/fundamentals.html#d5e143

Apache HttpClient版本:4.1.3

当我在Multithread环境(Servlets)中使用HttpClient时,我遇到了这个问题。 一个servlet仍然保持连接,另一个想要连接。

解:

版本4.0使用ThreadSafeClientConnManager

版本4.2使用PoolingClientConnectionManager

并设置了这两个引导者:

 setDefaultMaxPerRoute setMaxTotal 

由于response.getEntity()为null,因此HTTP HEAD请求必须稍微不同。 相反,您必须捕获传递到HttpClient.execute()的HttpContext并检索连接参数以closures它(无论如何HttpComponents 4.1.X)。

 HttpRequest httpRqst = new HttpHead( uri ); HttpContext httpContext = httpFactory.createContext(); HttpResponse httpResp = httpClient.execute( httpRqst, httpContext ); ... // Close when finished HttpEntity entity = httpResp.getEntity(); if( null != entity ) // Handles standard 'GET' case EntityUtils.consume( entity ); else { ConnectionReleaseTrigger conn = (ConnectionReleaseTrigger) httpContext.getAttribute( ExecutionContext.HTTP_CONNECTION ); // Handles 'HEAD' where entity is not returned if( null != conn ) conn.releaseConnection(); } 

HttpComponents 4.2.X增加了一个releaseConnection()到HttpRequestBase使这更容易。

我有同样的问题,并通过在方法结束时closures响应来解决它:

 try { // make the request and get the entity } catch(final Exception e) { // handle the exception } finally { if(response != null) { response.close(); } } 

我正在使用HttpClient 4.5.3,使用CloseableHttpClient#close为我工作。

  CloseableHttpResponse response = client.execute(request); try { HttpEntity entity = response.getEntity(); String body = EntityUtils.toString(entity); checkResult(body); EntityUtils.consume(entity); } finally { response.close(); } 

如果您想重新使用连接,那么您必须在每次使用后完全使用内容stream,如下所示:

 EntityUtils.consume(response.getEntity()) 

注意:即使状态码不是200,也需要使用内容stream。不这样做会在下次使用时引发以下情况:

线程“main”中的exceptionjava.lang.IllegalStateException:SingleClientConnManager的无效使用:连接仍然分配。 确保在分配另一个之前释放连接。

如果是一次性使用,那么简单地closures连接将释放与其关联的所有资源。