Java HttpClient 4.0.1-如何释放连接?
我在一堆URL上有一个循环,对于每一个URL,我都在执行以下操作:Java HttpClient 4.0.1-如何释放连接?,java,connection,apache-httpclient-4.x,Java,Connection,Apache Httpclient 4.x,我在一堆URL上有一个循环,对于每一个URL,我都在执行以下操作: private String doQuery(String url) { HttpGet httpGet = new HttpGet(url); setDefaultHeaders(httpGet); // static method HttpResponse response = httpClient.execute(httpGet); // httpClient instantiated in constr
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)
这只是一个简单的单线程应用程序。如何释放此连接?要回答我自己的问题:要释放连接(以及与请求相关的任何其他资源),必须关闭HttpEntity返回的InputStream:
InputStream is = entity.getContent();
.... process the input stream ....
is.close(); // releases all resources
从中,Httpcomponents 4.1推荐的方法是关闭连接并释放任何底层资源:
EntityUtils.consume(HttpEntity)
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
}
}
其中传递的
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();
}
参考资料:
Apache HttpClient版本:4.1.3自4.2版以来,他们引入了一种更方便的方法来简化连接发布:我在多线程环境(servlet)中使用HttpClient时遇到了这个问题。 一个servlet仍然保持连接,另一个servlet希望获得连接 解决方案: 版本4.0使用
ThreadSafeClientConnManager
版本4.2使用池客户端连接管理器
设置这两个设置器:
setDefaultMaxPerRoute
setMaxTotal
HTTP头请求的处理方式必须略有不同,因为response.getEntity()为null。 相反,您必须捕获传递到HttpClient.execute()的HttpContext并检索连接参数以关闭它(无论如何,在HttpComponents 4.1.X中)
HttpComponents 4.2.X在HttpRequestBase中添加了一个releaseConnection(),以简化此操作。我将提供一个详细的答案,专门针对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异常时自动释放基础连接 读取响应内容时引发。不需要特殊处理 在这种情况下需要 事实上,这完全足以确保适当释放资源:
EntityUtils.consume(HttpEntity)
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);
}
}
};
private ResponseHandler defaultHandler=new ResponseHandler(){
@凌驾
公共字符串句柄响应(HttpResponse响应)
抛出IOException{
int status=response.getStatusLine().getStatusCode();
如果(状态>=200&&status<300){
HttpEntity=response.getEntity();
返回实体!=null?EntityUtils.toString(实体):null;
}否则{
抛出新的ClientProtocolException(“意外响应状态:+状态”);
}
}
};
我不这么认为,我这样做了,我得到了“SingleClientConnManager的无效使用:连接仍然分配”。这可能是通过我可以从httpClient获得的ClientConnectionManager完成的,但它似乎不正确,我也是。你在重用httpClient吗?您如何确保它在请求失败时释放资源?我可以通过关闭InputStream来确认,我看到了调试消息:org.apache.http.impl.conn.BasicClientConnectionManager(18314):Releasing connectionI确认它工作正常。非常感谢。(顺便说一句,使用HttpComponents-4.1“EntityUtils.consume(httpEntity)”也可以完成这项工作)。Richard是对的,在接收到的输入流上调用“close()”,通知watcher关闭流,然后watcher关闭流本身并将连接标记为“可重用”(httpclient版本4.5.1)。这是4.1的正确答案。Richard H one的那个对我不起作用。我也面临着同样的问题。此解决方案有效,但并不涵盖所有可能的情况。我认为httpClient正在被重用。如果一些请求失败,正如您对HTTP所期望的那样,如何释放分配的资源还不清楚。即使遵循Apache提供的多个不同异常处理程序的示例,我仍然面临相同的问题:(@Rafael)您可以使用HttpRequestBa