HttpClient Timeout

1. Übersicht

Dieses Tutorial zeigt, wie Sie ein Timeout mit dem Apache HttpClient 4 konfigurieren .

Wenn Sie tiefer graben und andere coole Dinge lernen möchten, die Sie mit dem HttpClient tun können, gehen Sie zum Haupt- HttpClient- Tutorial .

2. Konfigurieren von Zeitüberschreitungen vor HttpClient 4.3

2.1. Raw- String- Parameter

Bevor Version 4.3 herauskam, enthielt der HttpClient viele Konfigurationsparameter, die alle generisch und kartenartig eingestellt werden konnten.

Es mussten 3 Timeout-Parameter konfiguriert werden :

DefaultHttpClient httpClient = new DefaultHttpClient(); int timeout = 5; // seconds HttpParams httpParams = httpClient.getParams(); httpParams.setParameter( CoreConnectionPNames.CONNECTION_TIMEOUT, timeout * 1000); httpParams.setParameter( CoreConnectionPNames.SO_TIMEOUT, timeout * 1000); httpParams.setParameter( ClientPNames.CONN_MANAGER_TIMEOUT, new Long(timeout * 1000));

2.2. API

Der wichtigere dieser Parameter - nämlich die ersten beiden - könnte auch über eine typsicherere API festgelegt werden:

DefaultHttpClient httpClient = new DefaultHttpClient(); int timeout = 5; // seconds HttpParams httpParams = httpClient.getParams(); HttpConnectionParams.setConnectionTimeout( httpParams, timeout * 1000); // http.connection.timeout HttpConnectionParams.setSoTimeout( httpParams, timeout * 1000); // http.socket.timeout

Der dritte Parameter hat keinen benutzerdefinierten Setter in HttpConnectionParams und muss weiterhin manuell über die setParameter- Methode festgelegt werden.

3. Konfigurieren Sie Timeouts mit dem neuen 4.3. Baumeister

Die in 4.3 eingeführte fließende Builder-API bietet die richtige Möglichkeit, Zeitüberschreitungen auf hohem Niveau festzulegen :

int timeout = 5; RequestConfig config = RequestConfig.custom() .setConnectTimeout(timeout * 1000) .setConnectionRequestTimeout(timeout * 1000) .setSocketTimeout(timeout * 1000).build(); CloseableHttpClient client = HttpClientBuilder.create().setDefaultRequestConfig(config).build();

Dies ist die empfohlene Methode, um alle drei Zeitüberschreitungen typsicher und lesbar zu konfigurieren.

4. Erläuterung der Timeout-Eigenschaften

Lassen Sie uns nun erklären, was diese verschiedenen Arten von Zeitüberschreitungen bedeuten:

  • das Verbindungszeitlimit ( http.connection.timeout ) - die Zeit zum Herstellen der Verbindung mit dem Remote-Host
  • das Socket-Timeout ( http.socket.timeout ) - die Wartezeit auf Daten - nach dem Herstellen der Verbindung; maximale Zeit der Inaktivität zwischen zwei Datenpaketen
  • Das Verbindungsmanager -Zeitlimit ( http.connection-manager.timeout ) - Die Zeit, die auf eine Verbindung vom Verbindungsmanager / Pool gewartet wird

Die ersten beiden Parameter - das Verbindungs- und das Socket-Timeout - sind die wichtigsten. Das Festlegen eines Zeitlimits zum Herstellen einer Verbindung ist jedoch in Szenarien mit hoher Last auf jeden Fall wichtig, weshalb der dritte Parameter nicht ignoriert werden sollte.

5. Verwenden des HttpClient

Nach der Konfiguration können wir jetzt den Client verwenden, um HTTP-Anforderungen auszuführen:

HttpGet getMethod = new HttpGet("//host:8080/path"); HttpResponse response = httpClient.execute(getMethod); System.out.println( "HTTP Status of response: " + response.getStatusLine().getStatusCode());

Mit dem zuvor definierten Client wird die Verbindung zum Host in 5 Sekunden unterbrochen. Wenn die Verbindung hergestellt wird, aber keine Daten empfangen werden, beträgt das Zeitlimit 5 zusätzliche Sekunden .

Beachten Sie, dass das Verbindungszeitlimit dazu führt, dass eine org.apache.http.conn.ConnectTimeoutException ausgelöst wird, während das Socket-Timeout zu einer java.net.SocketTimeoutException führt .

6. Harte Zeitüberschreitung

Während das Festlegen von Zeitlimits beim Herstellen der HTTP-Verbindung und beim Nichtempfangen von Daten sehr nützlich ist, müssen wir manchmal ein hartes Zeitlimit für die gesamte Anforderung festlegen .

Beispielsweise passt der Download einer möglicherweise großen Datei in diese Kategorie. In diesem Fall kann die Verbindung erfolgreich hergestellt werden, Daten werden möglicherweise konsistent übertragen, aber wir müssen weiterhin sicherstellen, dass der Vorgang einen bestimmten Zeitschwellenwert nicht überschreitet.

HttpClient verfügt über keine Konfiguration, mit der wir ein Gesamtzeitlimit für eine Anforderung festlegen können. Es bietet jedoch eine Abbruchfunktion für Anforderungen , sodass wir diesen Mechanismus nutzen können, um einen einfachen Timeout-Mechanismus zu implementieren:

HttpGet getMethod = new HttpGet( "//localhost:8080/httpclient-simple/api/bars/1"); int hardTimeout = 5; // seconds TimerTask task = new TimerTask() { @Override public void run() { if (getMethod != null) { getMethod.abort(); } } }; new Timer(true).schedule(task, hardTimeout * 1000); HttpResponse response = httpClient.execute(getMethod); System.out.println( "HTTP Status of response: " + response.getStatusLine().getStatusCode());

Wir verwenden java.util.Timer und java.util.TimerTask , um eine einfache verzögerte Task einzurichten, die die HTTP-GET-Anforderung nach einem 5-Sekunden-Timeout abbricht .

7. Timeout und DNS Round Robin - etwas, das Sie beachten sollten

Es ist durchaus üblich, dass einige größere Domänen eine DNS-Round-Robin-Konfiguration verwenden - im Wesentlichen wird dieselbe Domäne mehreren IP-Adressen zugeordnet . Dies stellt eine neue Herausforderung für ein Timeout für eine solche Domain dar, einfach weil HttpClient versucht, eine Verbindung zu dieser Domain herzustellen, die eine Zeitüberschreitung aufweist:

  • HttpClient ruft die Liste der IP-Routen zu dieser Domäne ab
  • es versucht das erste - das Timeout (mit den von uns konfigurierten Timeouts)
  • es versucht den zweiten - das läuft auch ab
  • und so weiter …

Wie Sie sehen, wird der Gesamtbetrieb nicht zeitlich begrenzt, wenn wir dies erwarten . Stattdessen tritt eine Zeitüberschreitung auf, wenn alle möglichen Routen abgelaufen sind. Darüber hinaus geschieht dies für den Client vollständig transparent (es sei denn, Sie haben Ihr Protokoll auf DEBUG-Ebene konfiguriert).

Hier ist ein einfaches Beispiel, mit dem Sie dieses Problem ausführen und replizieren können:

int timeout = 3; RequestConfig config = RequestConfig.custom(). setConnectTimeout(timeout * 1000). setConnectionRequestTimeout(timeout * 1000). setSocketTimeout(timeout * 1000).build(); CloseableHttpClient client = HttpClientBuilder.create() .setDefaultRequestConfig(config).build(); HttpGet request = new HttpGet("//www.google.com:81"); response = client.execute(request);

Sie werden die Wiederholungslogik mit einer DEBUG-Protokollebene bemerken:

DEBUG o.a.h.i.c.HttpClientConnectionOperator - Connecting to www.google.com/173.194.34.212:81 DEBUG o.a.h.i.c.HttpClientConnectionOperator - Connect to www.google.com/173.194.34.212:81 timed out. Connection will be retried using another IP address DEBUG o.a.h.i.c.HttpClientConnectionOperator - Connecting to www.google.com/173.194.34.208:81 DEBUG o.a.h.i.c.HttpClientConnectionOperator - Connect to www.google.com/173.194.34.208:81 timed out. Connection will be retried using another IP address DEBUG o.a.h.i.c.HttpClientConnectionOperator - Connecting to www.google.com/173.194.34.209:81 DEBUG o.a.h.i.c.HttpClientConnectionOperator - Connect to www.google.com/173.194.34.209:81 timed out. Connection will be retried using another IP address //...

8. Fazit

In diesem Lernprogramm wurde erläutert, wie Sie die verschiedenen Arten von Zeitüberschreitungen konfigurieren, die für einen HttpClient verfügbar sind . Es wurde auch ein einfacher Mechanismus für das Hard-Timeout einer laufenden HTTP-Verbindung dargestellt.

Die Implementierung dieser Beispiele finden Sie im GitHub-Projekt.