2017-09-05 4 views
0

In meinem Test-Anwendung ausführen ich in Folge HttpGet auf dem gleichen Host anfordert mit Apache Httpclient aber bei jedem nächsten Anforderung wird es stellt sich heraus, dass der vorherige Httpconnection geschlossen und der neue Httpconnection erstellt.Wie erhält man persistente HttpConnection mit Apache HttpClient?

Ich benutze die gleiche Instanz von HttpClient und schließen keine Antworten. Von jeder Entität erhalte ich InputStream, lese mit Scanner und schließe dann den Scanner. Ich habe KeepAliveStrategy getestet, es gibt True zurück. Die Zeit zwischen Anforderungen überschreitet nicht die Dauer von keepAlive oder connectionTimeToLive.

Kann mir jemand sagen, was könnte der Grund für ein solches Verhalten sein?

Aktualisiert

ich die Lösung gefunden zu haben. Um das HttpConnecton am Leben zu erhalten, ist es notwendig HttpClientConnectionManager beim Aufbau von HttpClient zu setzen. Ich habe BasicHttpClientConnectionManager verwendet.

ConnectionKeepAliveStrategy keepAliveStrat = new DefaultConnectionKeepAliveStrategy() { 
    @Override 
    public long getKeepAliveDuration(HttpResponse response, HttpContext context) 
    { 
     long keepAlive = super.getKeepAliveDuration(response, context); 
     if (keepAlive == -1) 
     keepAlive = 120000; 
     return keepAlive; 
    } 
}; 
HttpClientConnectionManager connectionManager = new BasicHttpClientConnectionManager(); 
try (CloseableHttpClient httpClient = HttpClients.custom() 
      .setConnectionManager(connectionManager) // without this setting connection is not kept alive 
      .setDefaultCookieStore(store) 
      .setKeepAliveStrategy(keepAliveStrat) 
      .setConnectionTimeToLive(120, TimeUnit.SECONDS) 
      .setUserAgent(USER_AGENT) 
      .build()) 
{ 
    HttpClientContext context = new HttpClientContext(); 
    RequestConfig config = RequestConfig.custom() 
      .setCookieSpec(CookieSpecs.DEFAULT) 
      .setSocketTimeout(10000) 
      .setConnectTimeout(10000) 
      .build(); 
    context.setRequestConfig(config); 
    HttpGet httpGet = new HttpGet(uri); 
    CloseableHttpResponse response = httpClient.execute(httpGet, context); 
    HttpConnection conn = context.getConnection(); 
    HttpEntity entity = response.getEntity(); 
    try (Scanner in = new Scanner(entity.getContent(), ENC)) 
    { 
     // do something 
    } 
    System.out.println("open=" + conn.isOpen()); // now open=true 

    HttpGet httpGet2 = new HttpGet(uri2); // on the same host with other path 

    // and so on 
} 

2 Aktualisiert

Im allgemeinen Überprüfung Verbindungen mit conn.isOpen() nicht richtige Weg ist, weil die Verbindungen Zustand zu überprüfen: „Intern HTTP-Verbindungs-Manager mit Instanzen von ManagedHttpClientConnection arbeiten als Proxy für einen echten handeln Verbindung, die den Verbindungsstatus verwaltet und die Ausführung von E/A-Vorgängen steuert Wenn eine verwaltete Verbindung freigegeben oder vom Benutzer explizit geschlossen wird, wird die zugrunde liegende Verbindung von ihrem Proxy getrennt und an den Manager zurückgegeben Ich habe einen Verweis auf die Proxy-Instanz, es ist nicht mehr in der Lage, irgendwelche E/A-Operationen auszuführen oder den Zustand der realen Verbindung entweder absichtlich oder unabsichtlich zu ändern. " (HttpClent Tutorial)

Wie schon @oleg gezeigt, ist der richtige Weg, Verbindungen zu verfolgen, die logger.

+0

Können Sie uns Code zeigen? – inovaovao

+0

Ja. Ich habe diesen Code hinzugefügt. – snptc

Antwort

1

Als Erstes müssen Sie sicherstellen, dass der Remote-Server, mit dem Sie arbeiten, Keep-Alive-Verbindungen unterstützt. Überprüfen Sie einfach, ob der entfernte Server in jeder Antwort den Header Connection: Keep-Alive oder Connection: Closed zurückgibt. Für Close Fall there is nothing können Sie damit umgehen. Sie können this online tool verwenden, um diese Überprüfung durchzuführen.

Als nächstes müssen Sie die ConnectionKeepAliveStrategy wie in Absatz # 2.6 von this manual definiert implementieren. Beachten Sie, dass Sie vorhandene DefaultConnectionKeepAliveStrategysince HttpClient version 4.0 verwenden können, so dass Ihre HttpClient wird wie folgt aufgebaut sein:

HttpClient client = HttpClients.custom() 
    .setKeepAliveStrategy(DefaultConnectionKeepAliveStrategy.INSTANCE) 
    .build(); 

, dass Sie sicherstellen, HttpClient Instanz die gleiche Verbindung über Keep-Alive-Mechanismus wiederverwenden, wenn sie vom Server unterstützt wird.

+0

Danke für die Antwort. Server gibt Verbindung zurück: keep-alive und ich benutze ConnectionKeepAliveStrategy. Deshalb verstehe ich nicht die Ursache der Verbindung schließen ... – snptc

+0

Können Sie bitte eine Methode oder ein Stück Code, die HTTP-Client erstellt und sendet dann aufeinander folgend ruft? – Kostiantyn

+0

Ja. Ich habe diesen Code hinzugefügt. – snptc

0

Ihre Anwendung muss Schließen Antwortobjekte, um eine ordnungsgemäße Ressourcenentziehung der zugrunde liegenden Verbindungen zu gewährleisten. Nach dem Schließen der Antwort hält HttpClient gültige Verbindungen am Leben und gibt sie an den Verbindungsmanager zurück (Verbindungspool).

Ich vermute, dass Ihr Code einfach Verbindungen verliert und jede Anfrage mit einer neu erstellten Verbindung beginnt, während alle vorherigen Verbindungen im Speicher weiter angehäuft werden.

+0

** oleg: ** * "Ihre Anwendung muss Antwortobjekte schließen, um eine ordnungsgemäße Ressourcen-Aufhebung der Zuordnung der zugrunde liegenden Verbindungen zu gewährleisten." * Aus dem offiziellen [HttpClient Tutorial] (https://hc.apache.org/ httpcomponents-client-ga/tutorial/html/fundamentals.html # d5e145): * "Der Unterschied zwischen dem Schließen des Inhaltsstroms und dem Schließen der Antwort besteht darin, dass ersterer versucht, die zugrunde liegende Verbindung durch den Konsum des Entitätsinhalts während des letzteren am Leben zu erhalten schaltet sich sofort ab und verwirft die Verbindung. "* Deshalb schließe ich den InputStream und nicht die Antwort selbst. – snptc

+0

Ich weiß, was das Tutorial sagt. Ich sehe deinen Code nicht, der InputStream irgendwo schließt. Ich sehe, dass der Scanner geschlossen wird, aber ich bin mir nicht sicher, ob dies auch zum Schließen von InputStream führt. Das Schließen der Antwort stellt sicher, dass die Verbindung zum Pool zurückgeht - egal was ist und ist die beste Vorgehensweise. – oleg

+0

Wenn Sie einigermaßen sicher sind, dass der Code keine Verbindung verliert, führen Sie ihn mit der Verbindungsmanagement-/Anfrageausführungsprotokollierung wie hier beschrieben aus http://hc.apache.org/httpcomponents-client-4.5.x/logging.html und Prüfen Sie, ob Verbindungen nach der Freigabe in den Pool beibehalten werden oder nicht – oleg

0

Aus dem Beispiel bei HttpClient website:

// In order to ensure correct deallocation of system resources 
// the user MUST call CloseableHttpResponse#close() from a finally clause. 
// Please note that if response content is not fully consumed the underlying 
// connection cannot be safely re-used and will be shut down and discarded 
// by the connection manager. 

So wie @oleg sagte Sie die Httpresponse schließen müssen, bevor Sie den Verbindungsstatus zu überprüfen.

+0

Ich habe es versucht. Das Ergebnis ist das gleiche ... Darüber hinaus gibt das HttpClient Tutorial an, dass das Schließen der Antwort die zugrunde liegende Verbindung schließen wird (siehe mein Kommentar oben). – snptc

Verwandte Themen