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?
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
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.
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!
Seit Version 4.2 wurde eine wesentlich bequemere Methode eingeführt, die die Verbindungsfreigabe vereinfacht: HttpRequestBase.releaseConnection ()
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.
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
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
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.
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();
}
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.
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);
}
}
};
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();
}
}