HttpClient 4.0.1-如何释放连接?

我有一个遍历一堆 URL 的循环,对于每个 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


}

第一个查询正常,第二个查询抛出这个异常:

线程“ main”中的异常 例外: 无效使用 连接 仍然分配。确保释放 分配之前的连接 另一个 GetConnection (SingleClientConnManager.java: 199) 在 ... ...

这只是一个简单的单线程应用程序。我如何释放这个连接?

152119 次浏览

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

InputStream is = entity.getContent();


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


is.close();       // releases all resources

来自 医生

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

EntityUtils.consume(HttpEntity)

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

这似乎很有效:

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

即使没有打开实体的内容,也不要忘记使用它。例如,您期望从响应中得到 HTTP _ OK 状态,但是没有得到它,您仍然必须使用该实体!

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

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

自从版本4.2以来,他们引入了一种更方便的方法来简化连接发布: RelaseConnection ()

我在多线程环境(Servlet)中使用 HttpClient 时遇到了这个问题。 一个 servlet 仍然保持连接,另一个 servlet 希望获得连接。

解决方案:

版本4.0使用 ThreadSafeClientConnManager

版本4.2使用 PoolingClientConnectionManager

设置这两个设置器:

setDefaultMaxPerRoute
setMaxTotal

HTTP HEAD 请求的处理方式必须略有不同,因为 response. getEntity ()为 null。 相反,您必须捕获传递到 HttpClient.execute ()的 HttpContext 并检索连接参数以关闭它(无论如何,在 HttpComponent 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();
}

HttpComponent 4.2.X 向 HttpRequestBase 添加了 release-Connection () ,使之更加简单。

我附和了一个详细的答案,它专门针对 Apache HttpClient 4.0.1。我正在使用这个 HttpClient 版本,因为它是由 WAS v8.0提供的,我需要使用 Apache Wink v1.1.1中提供的 HttpClient (也是 WAS v8.0提供的)来对 Sharepoint 进行一些经过 NTLM 身份验证的 REST 调用。

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

就是这样。

来源

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

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,使用 CloseableHttpResponse#close对我来说很有用。

    CloseableHttpResponse response = client.execute(request);


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

Java7及以上版本:

try (CloseableHttpResponse response = client.execute(request)) {
...
}

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

EntityUtils.consume(response.getEntity())

注意: 即使状态码不是200,您也需要使用内容流。如果不这样做,下次使用时将产生以下影响:

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

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

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

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