HttpClient 4.0.1 - как освободить соединение? - PullRequest
70 голосов
/ 23 января 2011

У меня есть цикл для нескольких 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

}

Первый запрос в порядке, второй выдает это исключение:

Исключение в теме "главная" 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 ]

95 голосов
/ 22 августа 2011

Рекомендуемый Httpcomponents 4.1 способ - закрыть соединение и освободить все базовые ресурсы:

EntityUtils.consume(HttpEntity)

, где HttpEntity передано - объект ответа.

32 голосов
/ 29 февраля 2012

Кажется, это прекрасно работает:

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

И не забывайте потреблять сущность, даже если вы не открывали ее содержимое. Например, вы ожидаете статус HTTP_OK от ответа и не получаете его, вам все равно придется использовать объект!

22 голосов
/ 23 января 2011

Чтобы ответить на мой собственный вопрос: чтобы освободить соединение (и любые другие ресурсы, связанные с запросом), вы должны закрыть InputStream, возвращаемый HttpEntity:

InputStream is = entity.getContent();

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

is.close();       // releases all resources

Из документов

19 голосов
/ 12 сентября 2012

Начиная с версии 4.2, они представили гораздо более удобный метод, который упрощает освобождение соединения: HttpRequestBase.releaseConnection ()

12 голосов
/ 11 апреля 2015

Я отвечаю подробным ответом, который конкретно касается Apache HttpClient 4.0.1. Я использую эту версию HttpClient, так как она предоставляется WAS v8.0, и мне нужно использовать предоставленный HttpClient в Apache Wink v1.1.1, также предоставляемый WAS v8.0, для выполнения некоторых проверенных NTLM REST-вызовов к 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
     } 
}

Вот и все.

Источник

7 голосов
/ 07 мая 2012

Если ответ не должен использоваться, запрос может быть прерван с помощью кода ниже:

// 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 голосов
/ 07 декабря 2012

У меня есть эта проблема, когда я использую HttpClient в среде Multithread (Servlets).Один сервлет все еще держит соединение, а другой хочет получить соединение.

Решение:

версия 4.0 использовать ThreadSafeClientConnManager

версия 4.2 использовать PoolingClientConnectionManager

и установить следующие два параметра:

setDefaultMaxPerRoute
setMaxTotal
2 голосов
/ 05 ноября 2014

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, чтобы упростить это.

1 голос
/ 31 августа 2017

Если вы хотите повторно использовать соединение, то вы должны полностью использовать поток контента после каждого использования следующим образом:

EntityUtils.consume(response.getEntity())

Примечание: вам нужно использовать поток контента, даже если код состояния не200. Если этого не сделать, при следующем использовании возникнет следующее:

Исключение в потоке "main" java.lang.IllegalStateException: Неправильное использование SingleClientConnManager: соединение все еще выделено.Обязательно освободите соединение, прежде чем выделять другое.

Если это одноразовое использование, то простое закрытие соединения освободит все ресурсы, связанные с ним.

1 голос
/ 03 апреля 2017

Я использую HttpClient 4.5.3, использую CloseableHttpClient#close, сработало для меня.

...