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