Java >> Java tutorial >  >> Tag >> HTTP

En hurtig guide til timeouts i OkHttp

1. Oversigt

I denne hurtige vejledning vil vi fokusere på forskellige typer timeouts, vi kan indstille for OkHttp-klienten.

For den mere generelle oversigt over OkHttp-biblioteket, se vores indledende OkHttp-guide.

2. Tilslutningstimeout

En forbindelsestimeout definerer en tidsperiode, hvor vores klient skal etablere en forbindelse med en målvært .

Som standard for OkHttpClient , er denne timeout indstillet til 10 sekunder .

Vi kan dog nemt ændre dens værdi ved hjælp af OkHttpClient.Builder#connectTimeout metode. En værdi på nul betyder ingen timeout overhovedet.

Lad os nu se, hvordan man bygger og bruger en OkHttpClient med en tilpasset forbindelsestimeout:

@Test
public void whenConnectTimeoutExceeded_thenSocketTimeoutException() {
    OkHttpClient client = new OkHttpClient.Builder()
      .connectTimeout(10, TimeUnit.MILLISECONDS)
      .build();

    Request request = new Request.Builder()
      .url("http://203.0.113.1") // non routable address
      .build();

    Throwable thrown = catchThrowable(() -> client.newCall(request).execute());

    assertThat(thrown).isInstanceOf(SocketTimeoutException.class);
}

Ovenstående eksempel viser, at klienten kaster en SocketTimeoutException når forbindelsesforsøget overskrider den konfigurerede timeout.

3. Læs timeout

En læsetimeout anvendes fra det øjeblik, forbindelsen mellem en klient og en målvært er blevet etableret.

Den definerer en maksimal tid for inaktivitet mellem to datapakker, når man venter på serverens svar .

Standard timeout på 10 sekunder kan ændres ved hjælp af OkHttpClient.Builder#readTimeout . Analogt som for forbindelses-timeout angiver en nulværdi ingen timeout.

Lad os nu se, hvordan man konfigurerer en brugerdefineret læsetimeout i praksis:

@Test
public void whenReadTimeoutExceeded_thenSocketTimeoutException() {
    OkHttpClient client = new OkHttpClient.Builder()
      .readTimeout(10, TimeUnit.MILLISECONDS)
      .build();

    Request request = new Request.Builder()
      .url("https://httpbin.org/delay/2") // 2-second response time
      .build();

    Throwable thrown = catchThrowable(() -> client.newCall(request).execute());

    assertThat(thrown).isInstanceOf(SocketTimeoutException.class);
}

Som vi kan se, returnerer serveren ikke svaret inden for den definerede timeout på 500 ms. Som følge heraf er OkHttpClient kaster en SocketTimeoutException.

4. Skriv timeout

En skrive-timeout definerer en maksimal tid for inaktivitet mellem to datapakker, når anmodningen sendes til serveren.

På samme måde, hvad angår forbindelses- og læsetimeout, kan vi tilsidesætte standardværdien på 10 sekunder ved hjælp af OkHttpClient.Builder#writeTimeout . Som en konvention betyder en nulværdi overhovedet ingen timeout.

I det følgende eksempel sætter vi en meget kort skrivetimeout på 10 ms og sender et indhold på 1 MB til serveren:

@Test
public void whenWriteTimeoutExceeded_thenSocketTimeoutException() {
    OkHttpClient client = new OkHttpClient.Builder()
      .writeTimeout(10, TimeUnit.MILLISECONDS)
      .build();

    Request request = new Request.Builder()
      .url("https://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);
}

Som vi ser, er vores klient på grund af den store nyttelast ikke i stand til at sende en anmodningstekst til serveren inden for den definerede timeout. Følgelig er OkHttpClient kaster en SocketTimeoutException .

5. Opkaldstimeout

En opkaldstimeout er en smule anderledes end de tilslutnings-, læse- og skrivetimeouts, vi allerede har diskuteret.

Det definerer en tidsgrænse for et komplet HTTP-kald . Dette inkluderer løsning af DNS, tilslutning, skrivning af anmodningsteksten, serverbehandling samt læsning af svarteksten.

I modsætning til andre timeouts er den standardværdi sat til nul, hvilket betyder ingen timeout . Men vi kan selvfølgelig konfigurere en tilpasset værdi ved hjælp af OkHttpClient.Builder#callTimeout metode.

Lad os se et eksempel på praktisk brug:

@Test
public void whenCallTimeoutExceeded_thenInterruptedIOException() {
    OkHttpClient client = new OkHttpClient.Builder()
      .callTimeout(1, TimeUnit.SECONDS)
      .build();

    Request request = new Request.Builder()
      .url("https://httpbin.org/delay/2")
      .build();

    Throwable thrown = catchThrowable(() -> client.newCall(request).execute());

    assertThat(thrown).isInstanceOf(InterruptedIOException.class);
}

Som vi kan se, er opkaldets timeout overskredet, og OkHttpClient kaster en InterruptedIOException.

6. Timeout pr. anmodning

Det anbefales at oprette en enkelt OkHttpClient instans og genbrug den til alle HTTP-kaldene på tværs af vores applikation.

Nogle gange ved vi dog, at en bestemt anmodning tager længere tid end alle andre. I denne situation skal vi forlænge en given timeout kun for det pågældende opkald .

I sådanne tilfælde kan vi bruge en OkHttpClient#newBuilder metode. Dette bygger en ny klient, der deler de samme indstillinger. Vi kan derefter bruge builder-metoderne til at justere timeout-indstillinger efter behov.

Lad os nu se, hvordan du gør dette i praksis:

@Test
public void whenPerRequestTimeoutExtended_thenResponseSuccess() throws IOException {
    OkHttpClient defaultClient = new OkHttpClient.Builder()
      .readTimeout(1, TimeUnit.SECONDS)
      .build();

    Request request = new Request.Builder()
      .url("https://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);
}

Som vi ser defaultClient kunne ikke fuldføre HTTP-kaldet på grund af overskredet læsetimeout.

Det er derfor, vi oprettede extendedTimeoutClient, justerede timeoutværdien og udførte anmodningen.

7. Resumé

I denne artikel undersøgte vi forskellige timeouts, vi kan konfigurere for OkHttpClient .

Vi har også kort beskrevet, hvornår forbindelses-, læse- og skrivetimeouts anvendes under et HTTP-kald.

Derudover viste vi, hvor nemt det er kun at ændre en bestemt timeoutværdi for en enkelt anmodning .

Som sædvanlig er alle kodeeksemplerne tilgængelige på GitHub.


Java tag