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连接将释放与其关联的所有资源。