HttpClient 4.0.1 - 如何释放连接?

时间:2011-01-23 18:35:58

标签: java connection apache-httpclient-4.x

我对一堆网址进行了循环,对于每一个我正在执行以下操作的网址:

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

}

第一个查询没问题,第二个查询抛出此异常:

  

线程“main”中的异常   java.lang.IllegalStateException:   使用无效   SingleClientConnManager:连接   仍然分配。一定要发布   分配前的连接   另一个。在   org.apache.http.impl.conn.SingleClientConnManager.getConnection(SingleClientConnManager.java:199)     在   org.apache.http.impl.conn.SingleClientConnManager $ 1.getConnection(SingleClientConnManager.java:173)......

这只是一个简单的单线程应用程序。我该如何发布此连接?

12 个答案:

答案 0 :(得分:94)

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

EntityUtils.consume(HttpEntity)

其中HttpEntity传递的是响应实体。

答案 1 :(得分:31)

这似乎很有效:

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

即使您没有打开其内容,也不要忘记使用该实体。例如,您希望响应中的HTTP_OK状态并且没有得到它,您仍然必须使用该实体!

答案 2 :(得分:22)

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

InputStream is = entity.getContent();

.... process the input stream ....

is.close();       // releases all resources

来自docs

答案 3 :(得分:18)

从版本4.2开始,他们引入了一种更简便的方法来简化连接释放:HttpRequestBase.releaseConnection()

答案 4 :(得分:12)

我正在寻找专门针对Apache HttpClient 4.0.1的详细解答。我正在使用这个HttpClient版本,因为它是由WAS v8.0提供的,我需要在Apache Wink v1.1.1中使用提供的HttpClient(也是由WAS v8.0提供)来制作一些NTLM -authenticated REST调用Sharepoint。

在Apache HttpClient邮件列表上引用Oleg Kalnichevski:

  

几乎所有这些代码都没有必要。 (1)HttpClient会   只要实体自动释放底层连接   内容被消耗到流的末尾; (2)HttpClient会   在任何I / O异常上自动释放底层连接   在阅读响应内容时抛出。没有特殊处理   在这种情况下需要。

     

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

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
     } 
}
     

就是这样。

Source

答案 5 :(得分:7)

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

// 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

答案 6 :(得分:4)

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

解决方案:

版本4.0使用ThreadSafeClientConnManager

版本4.2使用PoolingClientConnectionManager

并设置这两个二传手:

setDefaultMaxPerRoute
setMaxTotal

答案 7 :(得分:2)

HTTP HEAD请求的处理方式必须略有不同,因为response.getEntity()为null。 相反,您必须捕获传递给HttpClient.execute()的HttpContext并检索连接参数以关闭它(无论如何在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为HttpRequestBase添加了一个releaseConnection()以使其更容易。

答案 8 :(得分:1)

我正在使用HttpClient 4.5.3,使用$('input').on('ifChanged', function(event) { if($(".checkbox").is(":checked")) { $value = $(this).val(); } else if($(".checkbox").is(":not(:checked)")) { $value= $(this).val(); } }); 为我工作。

CloseableHttpClient#close

答案 9 :(得分:1)

如果要重新使用连接,则必须在每次使用后完全使用内容流,如下所示:

EntityUtils.consume(response.getEntity())

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

线程中的异常" main" java.lang.IllegalStateException:无效使用SingleClientConnManager:仍然分配了连接。确保在分配另一个连接之前释放连接。

如果它是一次性使用,那么只需关闭连接就会释放与之关联的所有资源。

答案 10 :(得分:0)

我遇到了同样的问题,并通过在方法结束时关闭响应来解决它:

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

答案 11 :(得分:0)

强烈建议使用处理程序来处理响应。

client.execute(yourRequest,defaultHanler);

它将使用consume(HTTPENTITY)方法自动释放连接。

处理程序示例:

private ResponseHandler<String> defaultHandler = new ResponseHandler<String>() {
    @Override
    public String handleResponse(HttpResponse response)
        throws IOException {
        int status = response.getStatusLine().getStatusCode();

        if (status >= 200 && status < 300) {
            HttpEntity entity = response.getEntity();
            return entity != null ? EntityUtils.toString(entity) : null;
        } else {
            throw new ClientProtocolException("Unexpected response status: " + status);
        }
    }
};