webentwicklung-frage-antwort-db.com.de

HttpClient 4.0.1 - Wie löse ich die Verbindung?

Ich habe eine Schleife über eine Reihe von URLs, für die ich jeweils Folgendes mache:

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

}

Die erste Abfrage ist in Ordnung, die zweite löst diese Ausnahme aus:

Ausnahme im Thread "main" Java.lang.IllegalStateException: Ungültige Verwendung von SingleClientConnManager: Verbindung noch zugeteilt. Stellen Sie sicher, dass .__ freigegeben wird. die Verbindung vor der Zuordnung noch einer. beim org.Apache.http.impl.conn.SingleClientConnManager.getConnection (SingleClientConnManager.Java:199) beim org.Apache.http.impl.conn.SingleClientConnManager $ 1.getConnection (SingleClientConnManager.Java:173) ......

Dies ist nur eine einfache Single-Threaded-App. Wie kann ich diese Verbindung freigeben?

68
Richard H

Um meine eigene Frage zu beantworten: Um die Verbindung (und andere mit der Anforderung verknüpfte Ressourcen) freizugeben, müssen Sie den von HttpEntity zurückgegebenen InputStream schließen:

InputStream is = entity.getContent();

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

is.close();       // releases all resources

Aus den Dokumenten

22
Richard H

Die empfohlene Methode von Httpcomponents 4.1 besteht darin, die Verbindung zu schließen und alle darunter liegenden Ressourcen freizugeben:

EntityUtils.consume(HttpEntity)

dabei ist HttpEntity eine Antwortentität.

92
Yadu

Das scheint großartig zu funktionieren:

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

Vergessen Sie nicht, die Entität zu konsumieren, auch wenn Sie deren Inhalt nicht geöffnet haben. Sie erwarten zum Beispiel einen HTTP_OK-Status aus der Antwort, und Sie erhalten ihn nicht. Sie müssen die Entität trotzdem konsumieren!

31
Snicolas

Seit Version 4.2 wurde eine wesentlich bequemere Methode eingeführt, die die Verbindungsfreigabe vereinfacht: HttpRequestBase.releaseConnection ()

18
wikier

Ich stimme mit einer ausführlichen Antwort zu, die speziell Apache HttpClient 4.0.1 anspricht. Ich verwende diese HttpClient-Version, da sie von WAS v8.0 bereitgestellt wird, und ich muss den bereitgestellten HttpClient in Apache Wink v1.1.1 verwenden, der ebenfalls von WAS v8.0 bereitgestellt wird, um NTLM-authentifiziert zu machen REST ruft Sharepoint auf.

So zitieren Sie Oleg Kalnichevski in der Apache HttpClient-Mailingliste:

So ziemlich alles ist nicht notwendig. (1) HttpClient wird Geben Sie die zugrunde liegende Verbindung automatisch frei, solange die Entität Inhalt wird bis zum Ende des Streams verbraucht; (2) HttpClient wird Geben Sie die zugrunde liegende Verbindung automatisch für jede E/A-Ausnahme frei wird beim Lesen des Antwortinhalts geworfen. Keine besondere Verarbeitung ist in einem solchen Fall erforderlich.

Tatsächlich reicht dies vollkommen aus, um die ordnungsgemäße Freigabe von Ressourcen sicherzustellen:

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

Das ist es.

Quelle

12
Chris Harris

Wenn die Antwort nicht verwendet werden soll, kann die Anforderung mit dem folgenden Code abgebrochen werden:

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

Reference: http://hc.Apache.org/httpcomponents-client-ga/tutorial/html/fundamentals.html#d5e143

Apache HttpClient Version: 4.1.3

7
Jignesh Gohel

Ich habe dieses Problem, wenn ich HttpClient in Multithread-Umgebungen (Servlets) verwende. Ein Servlet hält immer noch eine Verbindung und ein anderes möchte eine Verbindung erhalten. 

Lösung:  

version 4.0 verwenden ThreadSafeClientConnManager

version 4.2 verwenden PoolingClientConnectionManager

und setze diese zwei Setter: 

setDefaultMaxPerRoute
setMaxTotal
4
chris

HTTP HEAD - Anforderungen müssen etwas anders behandelt werden, da response.getEntity () den Wert null hat . Stattdessen müssen Sie den in HttpClient.execute () übergebenen HttpContext erfassen und den Verbindungsparameter abrufen (in HttpComponents 4.1.) .X trotzdem).

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 fügte releaseConnection () zu HttpRequestBase hinzu, um dies zu vereinfachen.

2
wbdarby

Ich verwende HttpClient 4.5.3, wobei CloseableHttpClient#close für mich gearbeitet hat.

    CloseableHttpResponse response = client.execute(request);

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

Wenn Sie die Verbindung erneut verwenden möchten, müssen Sie den Inhaltsstrom nach jeder Verwendung vollständig verbrauchen. Gehen Sie dazu wie folgt vor: 

EntityUtils.consume(response.getEntity())

Hinweis: Sie müssen den Content-Stream auch dann verbrauchen, wenn der Statuscode nicht 200 lautet. Andernfalls wird Folgendes bei der nächsten Verwendung angezeigt: 

Ausnahme im Thread "main" Java.lang.IllegalStateException: Ungültige Verwendung von SingleClientConnManager: Verbindung weiterhin zugewiesen. Stellen Sie sicher, dass Sie die Verbindung freigeben, bevor Sie eine weitere zuordnen. 

Wenn es sich um eine einmalige Verwendung handelt, werden durch das Schließen der Verbindung alle damit verbundenen Ressourcen freigegeben. 

1
Ayman Hussain

Es wird dringend empfohlen, einen Handler für die Antwort zu verwenden.

client.execute(yourRequest,defaultHanler);

Die Verbindung wird automatisch mit der consume(HTTPENTITY)-Methode freigegeben.

Ein Handler-Beispiel:

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

Ich hatte das gleiche Problem und löste es, indem ich die Antwort am Ende der Methode beendete:

try {
    // make the request and get the entity 
} catch(final Exception e) {
    // handle the exception
} finally {
    if(response != null) {
        response.close();
    }
}
0
kerl