Кратко ръководство за изчаквания в OkHttp

1. Общ преглед

В този бърз урок ще се съсредоточим върху различни видове изчаквания, които можем да зададем за клиента OkHttp.

За по-общ преглед на библиотеката OkHttp проверете нашето уводно ръководство за OkHttp.

2. Време за изчакване за свързване

Времето за свързване определя период от време, в който нашият клиент трябва да установи връзка с целевия хост .

По подразбиране за OkHttpClient това време за изчакване е зададено на 10 секунди .

Въпреки това можем лесно да променим стойността му, като използваме метода OkHttpClient.Builder # connectTimeout . Нулева стойност означава никакво изчакване.

Нека сега видим как да изградим и използваме OkHttpClient с персонализирано време за изчакване на връзката:

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

Горният пример показва, че клиентът изхвърля SocketTimeoutException, когато опитът за свързване надвиши конфигурираното време за изчакване.

3. Прочетете Timeout

Времето за изчакване за четене се прилага от момента, в който връзката между клиент и целеви хост е установена успешно.

Той дефинира максимално време на неактивност между два пакета с данни при изчакване на отговора на сървъра .

Времето за изчакване по подразбиране от 10 секунди може да бъде променено с помощта на OkHttpClient.Builder # readTimeout . Аналогично на времето за изчакване на свързването, нулева стойност показва липса на изчакване.

Нека сега видим как да конфигурираме персонализиран таймаут за четене на практика:

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

Както виждаме, сървърът не връща отговора в рамките на определеното време за изчакване от 500 ms. В резултат на това OkHttpClient изхвърля SocketTimeoutException.

4. Напишете таймаут

Времето за изчакване на запис определя максимално време на неактивност между два пакета данни при изпращане на заявката до сървъра.

По същия начин, що се отнася до изчакванията за свързване и четене, можем да заменим стойността по подразбиране от 10 секунди, използвайки OkHttpClient.Builder # writeTimeout . Като конвенция нулевата стойност означава никакво изчакване.

В следващия пример задаваме много кратко време за запис от 10 ms и публикуваме 1 MB съдържание на сървъра:

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

Както виждаме, поради големия полезен товар, нашият клиент не може да изпрати тяло на заявка до сървъра в рамките на определеното време за изчакване. Следователно OkHttpClient изхвърля SocketTimeoutException .

5. Време за изчакване на разговора

Времето за изчакване на разговора е малко по-различно от времето за свързване, четене и запис, което вече обсъдихме.

Той определя срок за цялостно HTTP повикване . Това включва разрешаване на DNS, свързване, писане на тялото на заявката, обработка на сървъра, както и четене на тялото на отговора.

За разлика от другите изчаквания, стойността по подразбиране е зададена на нула, което означава, че няма изчакване . Но разбира се, можем да конфигурираме персонализирана стойност, като използваме метода OkHttpClient.Builder # callTimeout .

Нека да видим практически пример за използване:

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

Както виждаме, времето за изчакване на повикването е надвишено и OkHttpClient изхвърля InterruptIOException.

6. Време за изчакване по заявка

Препоръчително е да създадете единичен екземпляр OkHttpClient и да го използвате повторно за всички HTTP повиквания в нашето приложение.

Понякога обаче знаем, че определена заявка отнема повече време от всички останали. В тази ситуация трябва да удължим даден таймаут само за конкретното обаждане .

В такива случаи можем да използваме метод OkHttpClient # newBuilder . Това създава нов клиент, който споделя същите настройки. След това можем да използваме методите на конструктора, за да коригираме настройките за изчакване при необходимост.

Нека сега видим как да направим това на практика:

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

Както виждаме, defaultClient не успя да завърши HTTP повикването поради превишеното изчакване за четене.

Ето защо създадохме extensionTimeoutClient, коригирахме стойността на времето за изчакване и успешно изпълнихме заявката.

7. Обобщение

В тази статия разгледахме различни таймаути, които можем да конфигурираме за OkHttpClient .

Също така накратко описахме кога се прилагат времеви изчаквания за свързване, четене и запис по време на HTTP повикване.

Освен това показахме колко лесно е да промените определена стойност за изчакване само за една заявка .

Както обикновено, всички примери за кодове са достъпни в GitHub.