Délai d'expiration HttpClient

1. Vue d'ensemble

Ce tutoriel montrera comment configurer un délai d'expiration avec Apache HttpClient 4 .

Si vous souhaitez approfondir et apprendre d'autres choses intéressantes que vous pouvez faire avec HttpClient, rendez-vous au didacticiel principal HttpClient .

2. Configuration des délais avant HttpClient 4.3

2.1. Paramètres de chaîne bruts

Avant la sortie de la version 4.3, le HttpClient était livré avec de nombreux paramètres de configuration, et tous pouvaient être définis de manière générique, semblable à une carte.

Il y avait 3 paramètres de délai d'expiration à configurer :

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

Le plus important de ces paramètres - à savoir les deux premiers - pourrait également être défini via une API plus sûre de type:

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

Le troisième paramètre n'a pas de setter personnalisé dans HttpConnectionParams , et il devra toujours être défini manuellement via la méthode setParameter .

3. Configurer les délais à l'aide du nouveau 4.3. Constructeur

L'API de création fluide introduite dans la version 4.3 fournit le bon moyen de définir des délais d'expiration à un niveau élevé :

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

C'est la manière recommandée de configurer les trois délais d'expiration d'une manière sûre et lisible.

4. Explication des propriétés de temporisation

Maintenant, expliquons ce que signifient ces différents types de délais:

  • le Délai d' expiration de la connexion ( http.connection.timeout ) - le temps pour établir la connexion avec l'hôte distant
  • le Socket Timeout ( http.socket.timeout ) - le temps d'attente des données - après l'établissement de la connexion; temps maximal d'inactivité entre deux paquets de données
  • le délai d'expiration du gestionnaire de connexion ( http.connection-manager.timeout ) - le temps d'attente pour une connexion depuis le gestionnaire / pool de connexions

Les deux premiers paramètres - les délais de connexion et de socket - sont les plus importants. Cependant, définir un délai pour obtenir une connexion est certainement important dans les scénarios de charge élevée, c'est pourquoi le troisième paramètre ne doit pas être ignoré.

5. Utilisation de HttpClient

Après l'avoir configuré, nous pouvons maintenant utiliser le client pour effectuer des requêtes HTTP:

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

Avec le client précédemment défini, la connexion à l'hôte expirera dans 5 secondes. De plus, si la connexion est établie mais qu'aucune donnée n'est reçue, le délai d'expiration sera également de 5 secondes supplémentaires .

Notez que le délai d'expiration de la connexion entraînera la levée d' une exception org.apache.http.conn.ConnectTimeoutException , tandis que le délai d'expiration du socket entraînera une exception java.net.SocketTimeoutException .

6. Délai d'attente difficile

Bien que la définition de délais d'expiration lors de l'établissement de la connexion HTTP et de la non-réception de données soit très utile, nous devons parfois définir un délai d'expiration fixe pour l'ensemble de la requête .

Par exemple, le téléchargement d'un fichier potentiellement volumineux entre dans cette catégorie. Dans ce cas, la connexion peut être établie avec succès, les données peuvent être transmises de manière cohérente, mais nous devons toujours nous assurer que l'opération ne dépasse pas un certain seuil de temps spécifique.

HttpClient n'a aucune configuration qui nous permet de définir un délai d'expiration global pour une requête; il fournit cependant une fonctionnalité d'abandon pour les demandes , nous pouvons donc tirer parti de ce mécanisme pour implémenter un mécanisme de délai d'expiration simple:

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

Nous utilisons java.util.Timer et java.util.TimerTask pour configurer une simple tâche retardée qui annule la requête HTTP GET après un délai d'attente de 5 secondes.

7. Timeout et DNS Round Robin - quelque chose dont il faut être conscient

Il est assez courant que certains domaines plus importants utilisent une configuration DNS round robin - ayant essentiellement le même domaine mappé à plusieurs adresses IP . Cela introduit un nouveau défi pour un délai d'expiration contre un tel domaine, simplement à cause de la façon dont HttpClient essaiera de se connecter à ce domaine qui expire:

  • HttpClient obtient la liste des routes IP vers ce domaine
  • il essaie le premier - qui expire (avec les délais que nous configurons)
  • il essaie le second - qui expire également
  • etc …

Ainsi, comme vous pouvez le voir, l'opération globale ne s'arrêtera pas lorsque nous nous y attendons . Au lieu de cela, il expirera lorsque tous les itinéraires possibles auront expiré. De plus, cela se produira de manière totalement transparente pour le client (à moins que votre journal ne soit configuré au niveau DEBUG).

Voici un exemple simple que vous pouvez exécuter et répliquer ce problème:

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

Vous remarquerez la logique de nouvelle tentative avec un niveau de journal DEBUG:

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. Conclusion

Ce didacticiel explique comment configurer les différents types de délais d' expiration disponibles pour un HttpClient . Il a également illustré un mécanisme simple pour le délai d'expiration dur d'une connexion HTTP en cours.

L'implémentation de ces exemples peut être trouvée dans le projet GitHub.