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
}
Первый запрос прекрасен, второй - это исключение:
Исключение в потоке "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)......
Это просто однопоточное приложение. Как я могу освободить это соединение?
Ответы
Ответ 1
Чтобы ответить на мой собственный вопрос: чтобы освободить соединение (и любые другие ресурсы, связанные с запросом), вы должны закрыть InputStream, возвращаемый HttpEntity:
InputStream is = entity.getContent();
.... process the input stream ....
is.close(); // releases all resources
Из docs
Ответ 2
Рекомендуемый способ, Httpcomponents 4.1, заключается в том, чтобы закрыть соединение и освободить любые базовые ресурсы:
EntityUtils.consume(HttpEntity)
где HttpEntity
передается объект ответа.
Ответ 3
Это, кажется, отлично работает:
if( response.getEntity() != null ) {
response.getEntity().consumeContent();
}//if
И не забывайте потреблять объект, даже если вы не открыли его содержимое. Например, вы ожидаете статус HTTP_OK из ответа и не получаете его, вам все равно придется использовать объект!
Ответ 4
Начиная с версии 4.2, они ввели гораздо более удобный метод, упрощающий выпуск соединения: HttpRequestBase.releaseConnection()
Ответ 5
Я читаю подробный ответ, в котором конкретно рассматривается Apache HttpClient 4.0.1. Я использую эту версию HttpClient, так как она предоставляется WAS v8.0, и мне нужно использовать предоставленный HttpClient в Apache Wink v1.1.1, также предоставляемый WAS v8.0, чтобы сделать некоторые вызовы REST с проверкой NTLM на Sharepoint,
Процитировать Олега Калничевского в списке рассылки Apache HttpClient:
Практически весь этот код не нужен. (1) HttpClient автоматически освободит базовое соединение до тех пор, пока контент объекта будет потреблен до конца потока; (2) HttpClient автоматически освободит базовое соединение при любом исключении ввода-вывода, которое выдается при чтении содержимого ответа. Никакой специальной обработки не требуется в таком случае.
На самом деле этого вполне достаточно для обеспечения надлежащего выпуска ресурсов:
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
}
}
Вот и все.
Источник
Ответ 6
Если ответ не должен быть использован, запрос можно прервать, используя следующий код:
// 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
Ответ 7
У меня есть эта проблема, когда я использую HttpClient в многопоточном envirnoment (Servlets).
Один сервлет по-прежнему содержит соединение, а другой хочет получить соединение.
Решение:
версия 4.0 использовать ThreadSafeClientConnManager
версия 4.2 используйте PoolingClientConnectionManager
и установите эти два сеттера:
setDefaultMaxPerRoute
setMaxTotal
Ответ 8
Запросы HTTP HEAD должны обрабатываться несколько иначе, потому что response.getEntity() имеет значение NULL.
Вместо этого вы должны захватить HttpContext, переданный в HttpClient.execute(), и получить параметр соединения, чтобы закрыть его (в любом случае в 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, чтобы сделать это проще.
Ответ 9
У меня была такая же проблема и она была решена, закрыв ответ в конце метода:
try {
// make the request and get the entity
} catch(final Exception e) {
// handle the exception
} finally {
if(response != null) {
response.close();
}
}
Ответ 10
Я использую 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();
}
Ответ 11
Если вы хотите повторно использовать соединение, то вы должны потреблять поток контента полностью после каждого использования следующим образом:
EntityUtils.consume(response.getEntity())
Примечание: вам нужно потреблять поток контента, даже если код состояния не равен 200. Не будет сделано следующее при следующем использовании:
Исключение в потоке "main" java.lang.IllegalStateException: Недействительное использование SingleClientConnManager: соединение все еще выделено. Обязательно отпустите соединение, прежде чем выделять другой.
Если это одноразовое использование, то просто закрытие соединения освободит все связанные с ним ресурсы.
Ответ 12
Очень рекомендую использовать обработчик для обработки ответа.
client.execute(yourRequest,defaultHanler);
Он автоматически освободит соединение с consume(HTTPENTITY)
метода 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);
}
}
};