Un guide rapide des délais d'expiration dans OkHttp

1. Vue d'ensemble

Dans ce rapide didacticiel, nous allons nous concentrer sur différents types de délais que nous pouvons définir pour le client OkHttp.

Pour un aperçu plus général de la bibliothèque OkHttp, consultez notre guide d'introduction OkHttp.

2. Délai de connexion

Un délai de connexion définit une période pendant laquelle notre client doit établir une connexion avec un hôte cible .

Par défaut, pour OkHttpClient , ce délai est défini sur 10 secondes .

Cependant, nous pouvons facilement modifier sa valeur en utilisant la méthode OkHttpClient.Builder # connectTimeout . Une valeur de zéro signifie aucun délai d'expiration.

Voyons maintenant comment créer et utiliser un OkHttpClient avec un délai d'expiration de connexion personnalisé:

@Test public void whenConnectTimeoutExceeded_thenSocketTimeoutException() { OkHttpClient client = new OkHttpClient.Builder() .connectTimeout(10, TimeUnit.MILLISECONDS) .build(); Request request = new Request.Builder() .url("//203.0.113.1") // non routable address .build(); Throwable thrown = catchThrowable(() -> client.newCall(request).execute()); assertThat(thrown).isInstanceOf(SocketTimeoutException.class); }

L'exemple ci-dessus montre que le client lève une exception SocketTimeoutException lorsque la tentative de connexion dépasse le délai d'attente configuré.

3. Délai de lecture

Un délai de lecture est appliqué à partir du moment où la connexion entre un client et un hôte cible a été établie avec succès.

Il définit une durée maximale d'inactivité entre deux paquets de données lors de l'attente de la réponse du serveur .

Le délai d'expiration par défaut de 10 secondes peut être modifié à l'aide de OkHttpClient.Builder # readTimeout . De la même manière que pour le délai de connexion, une valeur nulle indique qu'il n'y a pas de délai.

Voyons maintenant comment configurer un délai de lecture personnalisé en pratique:

@Test public void whenReadTimeoutExceeded_thenSocketTimeoutException() { OkHttpClient client = new OkHttpClient.Builder() .readTimeout(10, TimeUnit.MILLISECONDS) .build(); Request request = new Request.Builder() .url("//httpbin.org/delay/2") // 2-second response time .build(); Throwable thrown = catchThrowable(() -> client.newCall(request).execute()); assertThat(thrown).isInstanceOf(SocketTimeoutException.class); }

Comme nous pouvons le voir, le serveur ne renvoie pas la réponse dans le délai défini de 500 ms. Par conséquent, OkHttpClient lève une exception SocketTimeoutException.

4. Délai d'écriture

Un délai d'écriture définit une durée maximale d'inactivité entre deux paquets de données lors de l'envoi de la requête au serveur.

De même, comme pour les délais de connexion et de lecture, nous pouvons remplacer la valeur par défaut de 10 secondes en utilisant OkHttpClient.Builder # writeTimeout . Par convention, une valeur nulle signifie qu'il n'y a aucun délai d'expiration.

Dans l'exemple suivant, nous définissons un délai d'écriture très court de 10 ms et publions un contenu de 1 Mo sur le serveur:

@Test public void whenWriteTimeoutExceeded_thenSocketTimeoutException() { OkHttpClient client = new OkHttpClient.Builder() .writeTimeout(10, TimeUnit.MILLISECONDS) .build(); Request request = new Request.Builder() .url("//httpbin.org/delay/2") .post(RequestBody.create(MediaType.parse("text/plain"), create1MBString())) .build(); Throwable thrown = catchThrowable(() -> client.newCall(request).execute()); assertThat(thrown).isInstanceOf(SocketTimeoutException.class); }

Comme nous le voyons, en raison de la charge utile importante, notre client n'est pas en mesure d'envoyer un corps de requête au serveur dans le délai imparti. Par conséquent, OkHttpClient lève une exception SocketTimeoutException .

5. Délai d'appel

Un délai d'attente d'appel est un peu différent des délais d'attente de connexion, de lecture et d'écriture dont nous avons déjà parlé.

Il définit une limite de temps pour un appel HTTP complet . Cela inclut la résolution du DNS, la connexion, l'écriture du corps de la requête, le traitement du serveur, ainsi que la lecture du corps de la réponse.

Contrairement à d'autres délais, sa valeur par défaut est définie sur zéro, ce qui n'implique aucun délai . Mais bien sûr, nous pouvons configurer une valeur personnalisée à l'aide de la méthode OkHttpClient.Builder # callTimeout .

Voyons un exemple d'utilisation pratique:

@Test public void whenCallTimeoutExceeded_thenInterruptedIOException() { OkHttpClient client = new OkHttpClient.Builder() .callTimeout(1, TimeUnit.SECONDS) .build(); Request request = new Request.Builder() .url("//httpbin.org/delay/2") .build(); Throwable thrown = catchThrowable(() -> client.newCall(request).execute()); assertThat(thrown).isInstanceOf(InterruptedIOException.class); }

Comme nous pouvons le voir, le délai d'expiration de l'appel est dépassé et le OkHttpClient lève une InterruptedIOException.

6. Délai d'expiration par demande

Il est recommandé de créer une seule instance OkHttpClient et de la réutiliser pour tous les appels HTTP dans notre application.

Parfois, cependant, nous savons qu'une certaine demande prend plus de temps que toutes les autres. Dans cette situation, nous devons prolonger un délai d'expiration donné uniquement pour cet appel particulier .

Dans de tels cas, nous pouvons utiliser une méthode OkHttpClient # newBuilder . Cela crée un nouveau client qui partage les mêmes paramètres. Nous pouvons ensuite utiliser les méthodes du générateur pour ajuster les paramètres de délai d'expiration selon les besoins.

Voyons maintenant comment faire cela en pratique:

@Test public void whenPerRequestTimeoutExtended_thenResponseSuccess() throws IOException { OkHttpClient defaultClient = new OkHttpClient.Builder() .readTimeout(1, TimeUnit.SECONDS) .build(); Request request = new Request.Builder() .url("//httpbin.org/delay/2") .build(); Throwable thrown = catchThrowable(() -> defaultClient.newCall(request).execute()); assertThat(thrown).isInstanceOf(InterruptedIOException.class); OkHttpClient extendedTimeoutClient = defaultClient.newBuilder() .readTimeout(5, TimeUnit.SECONDS) .build(); Response response = extendedTimeoutClient.newCall(request).execute(); assertThat(response.code()).isEqualTo(200); }

Comme nous le voyons, defaultClient n'a pas réussi à terminer l'appel HTTP en raison du dépassement du délai de lecture.

C'est pourquoi nous avons créé le extendedTimeoutClient, ajusté la valeur du délai d'expiration et exécuté avec succès la demande.

7. Résumé

Dans cet article, nous avons exploré différents délais d' expiration que nous pouvons configurer pour OkHttpClient .

Nous avons également brièvement décrit quand les délais de connexion, de lecture et d'écriture sont appliqués lors d'un appel HTTP.

De plus, nous avons montré à quel point il est facile de modifier une certaine valeur de délai d'expiration uniquement pour une seule demande .

Comme d'habitude, tous les exemples de code sont disponibles à l'adresse over sur GitHub.