OkHttp е високопроизводителен HTTP клиент за Android и Kotlin, разработен от компанията Square като основа за Retrofit и други мрежови библиотеки. Той осигурява ефективно управление на връзките, вградено кеширане и поддръжка на HTTP/2. По данни на Square, 2025, OkHttp обработва милиарди заявки дневно в приложения по целия свят.
Основни моменти
OkHttp е ефективен HTTP клиент за Java, Android и Kotlin, разработен от Square. Библиотеката предоставя нискониво API за изпълнение на HTTP заявки с поддръжка на HTTP/2, SPDY, WebSocket и автоматично възстановяване на връзките при мрежови повреди.
OkHttp се появи през 2013 г. като отговор на нуждата от надежден HTTP клиент, който да реши проблемите на HttpURLConnection — липса на пул от връзки, слаба поддръжка на HTTP/2 и неудобно API. До 2025 г. OkHttp се използва на системно ниво в Android API: OkHttp е вграден в имплементацията на HttpURLConnection от Android 4.4 (API 19).
Според данни от Google I/O 2024, OkHttp обработва над 70% от всички HTTP заявки в екосистемата на Android. Това е възможно, защото OkHttp е транспортният слой за Retrofit, Apollo GraphQL, Firebase и много други библиотеки. Разработчиците получават функционалността на OkHttp автоматично, без изрично да го свързват.
Архитектурата на OkHttp е изградена върху верига от прихващачи (Interceptor chain). Всяка заявка преминава през последователност от прихващачи, които могат да модифицират Request, Response или да прекъснат изпълнението. Тази архитектура напомня на шаблона Chain of Responsibility и позволява гъвкаво разширяване на функционалността.
Когато приложението изпраща заявка, OkHttp изпълнява следните стъпки: разрешава DNS, избира връзка от пула (или създава нова), отваря TLS ръкостискане (ако е HTTPS), изпраща HTTP заявка, получава отговор и го връща на приложението. RealCall е вътрешен клас, който управлява пълния жизнен цикъл на заявката от създаване до завършване.
OkHttp автоматично обработва пренасочвания (302, 301), повтаря заявки при мрежови повреди (retry), следва протокола keep-alive и поддържа прозрачна gzip компресия. Разработчикът не трябва да пише код за тези операции — OkHttp ги извършва автоматично въз основа на хедърите на сървъра.
HTTP/2 позволява изпращане на множество заявки чрез една TCP връзка едновременно, без блокиране (head-of-line blocking, характерен за HTTP/1.1). OkHttp автоматично използва HTTP/2, ако сървърът поддържа този протокол, и прозрачно превключва към HTTP/1.1 при необходимост.
Мултиплексирането на HTTP/2 е особено важно за мобилни приложения, където забавянето при установяване на връзка (TCP + TLS) може да бъде 100–300 ms. Вместо 10 последователни връзки, OkHttp използва една, намалявайки общото забавяне с 40–60% на типични Android устройства с нестабилна връзка.
Interceptor е интерфейс с единствен метод intercept(Chain), който получава Request, изпълнява действия и връща Response. Прихващачите са два типа: приложни прихващачи (добавят се чрез addInterceptor) и мрежови прихващачи (addNetworkInterceptor).
Приложните прихващачи се активират преди формиране на HTTP заявката — те виждат оригиналния Request и крайния Response след всички трансформации. Мрежовите прихващачи се активират на мрежово ниво: те виждат заявката след gzip компресия, добавяне на Content-Length хедъри, пренасочвания и повторни опити. Мрежовите прихващачи не се извикват, ако отговорът е получен от кеша.
| Тип прихващач | Метод на добавяне | Кога се извиква | Вижда кеш |
|---|---|---|---|
| Application Interceptor | addInterceptor() | Преди и след заявка | Да |
| Network Interceptor | addNetworkInterceptor() | На мрежово ниво | Не |
На практика прихващачите на OkHttp решават три основни задачи: оторизация (добавяне на Authorization хедър), логване (HttpLoggingInterceptor за отстраняване на грешки) и повторен опит (автоматично повтаряне на заявка при мрежови повреди). Комбинирайки няколко прихващача, може да се изгради пълен pipeline за обработка на заявки без дублиране на код във всяко HTTP извикване на приложението.
Редът на добавяне на прихващачите има значение: Interceptor, добавен първи, се изпълнява първи на входа и последен на изхода. За NetworkInterceptor редът се определя от мрежовия стек. Препоръчителен ред: AuthInterceptor (добавя токен), LoggingInterceptor (логва заявката), RetryInterceptor (повтаря при повреди).
За отстраняване на грешки в мрежови заявки се използва HttpLoggingInterceptor — готов прихващач от Square. Той логва метода, URL, хедърите и тялото на заявката и отговора. Нива на логване: BASIC (метод + URL + код), HEADERS (с хедъри) и BODY (пълна заявка и отговор). BODY е полезен по време на разработка, но в продукция се изключва от съображения за сигурност и производителност.
Нека разгледаме основна GET заявка чрез OkHttp. Първо се създава OkHttpClient — тежък обект, който се създава веднъж и се използва повторно. След това се формира Request с URL и заявката се изпълнява синхронно чрез execute или асинхронно чрез enqueue.
val client = OkHttpClient.Builder()
.connectTimeout(15, TimeUnit.SECONDS)
.readTimeout(15, TimeUnit.SECONDS)
.build()
val request = Request.Builder()
.url("https://api.github.com/users/octocat")
.header("Accept", "application/vnd.github.v3+json")
.build()
val response = client.newCall(request).execute()
println(response.body()?.string())
За асинхронно изпълнение се използва методът enqueue, който приема Callback. OkHttp изпълнява заявката във фонова нишка и връща резултата в callback на същата нишка. За превключване към главната нишка на Android използвайте Handler или корутини.
client.newCall(request).enqueue(object : Callback {
override fun onFailure(
call: Call, e: IOException
) {
println("Заявката не успя: ${e.message}")
}
override fun onResponse(
call: Call, response: Response
) {
println(response.body()?.string())
}
})
Персонализиран Interceptor добавя Bearer токен към всяка заявка. Прихващачът проверява наличието на Authorization хедър и ако токенът все още не е зададен, го добавя от хранилището. При отговор 401, прихващачът може да обнови токена чрез Authenticator.
class AuthInterceptor(
private val tokenProvider: () -> String?
) : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val originalRequest = chain.request()
val token = tokenProvider.invoke()
val request = originalRequest.newBuilder()
.header("Authorization", "Bearer $token")
.build()
return chain.proceed(request)
}
}
Пулът от връзки (ConnectionPool) — ключова оптимизация на OkHttp, която позволява повторно използване на TCP връзки за множество заявки. Вместо да създава нов сокет за всяка заявка, OkHttp съхранява до 5 неактивни връзки (по подразбиране) за 5 минути, което намалява забавянето с 30–70% за повторни заявки към същия хост.
Кеширането на отговори се реализира чрез класа Cache. За включване на кеша е достатъчно да посочите директория и максимален размер в OkHttpClient.Builder. OkHttp автоматично кешира GET отговори според Cache-Control, Expires и ETag хедърите, връщайки кеширани данни без мрежова заявка, ако не са изтекли.
val cacheDir = File(context.cacheDir, "http-cache")
val cache = Cache(cacheDir, 10L * 1024 * 1024)
val client = OkHttpClient.Builder()
.cache(cache)
.connectionPool(ConnectionPool(5, 5, TimeUnit.MINUTES))
.build()
Правилното конфигуриране на пула и кеша е особено важно за приложения с чести заявки — новинарски емисии, чатове, актуализации на данни. Без пул всяка TCP връзка изисква трипосочно ръкостискане (SYN, SYN-ACK, ACK) и потенциално TLS ръкостискане (2–3 round-trip), което добавя 100–500 ms към всяка заявка.
OkHttp също поддържа WebSocket чрез класа RealWebSocket. WebSocket връзката се установява чрез HTTP ръкостискане (101 Switching Protocols) и след това превключва към двупосочен протокол. OkHttp автоматично изпраща ping рамки за поддържане на връзката жива и се пресвързва при прекъсване. WebSocket от OkHttp е съвместим със стандартни крайни точки като wss://echo.websocket.org.
Създаване на OkHttpClient за всяка заявка — най-честата грешка. OkHttpClient съдържа пула от връзки, кеша и пула от нишки. Създаването на нов екземпляр за всяка заявка не само губи памет, но и лишава от предимството на повторното използване на връзки. OkHttpClient трябва да бъде сингълтън чрез DI контейнер.
Пренебрегване на затварянето на Response.body() води до изтичане на ресурси. ResponseBody съдържа InputStream, който трябва да се затвори след прочитане. Ако се използва body().string() или body().bytes(), OkHttp затваря потока автоматично, но при четене на body().byteStream() или body().charStream() се изисква изрично извикване на close() в блок finally.
Липса на обработка на Timeout — друг проблем. По подразбиране OkHttp няма таймаути (connectTimeout = 10 секунди, readTimeout = 10 секунди, writeTimeout = 10 секунди). За мобилни приложения с нестабилна връзка се препоръчва настройка на connectTimeout 15–30 секунди и readTimeout 15–30 секунди, в противен случай потребителят ще чака твърде дълго при слаб сигнал.
Често задавани въпроси
OkHttp е нискониво HTTP клиент с ръчно управление на Request и Response. Retrofit е високониво обвивка с анотации. OkHttp се използва като транспорт за Retrofit, но може да работи самостоятелно без допълнителни библиотеки.
OkHttp използва SSLSocketFactory за TLS ръкостискане. Библиотеката поддържа CertificatePinner за закрепване на сертификати (Certificate Pinning), TrustManager за персонализирано валидиране и HostnameVerifier за проверка на името на хоста спрямо сертификата.
Синхронните заявки хвърлят IOException при мрежови проблеми. Асинхронните заявки получават извикване onFailure с IOException. За HTTP грешки (4xx, 5xx) отговорът се счита за успешен — кодът на грешката се проверява чрез response.isSuccessful().
Да, OkHttp има вградена поддръжка за WebSocket чрез класовете WebSocket и WebSocketListener. След установяване на връзка, WebSocket позволява изпращане и получаване на съобщения в реално време без повторни HTTP заявки.
Изключете автоматичните пренасочвания чрез followRedirects(false) и followSslRedirects(false) в OkHttpClient.Builder. Това е полезно, когато трябва ръчно да обработите пренасочване, например за извличане на токен от URL за пренасочване.
Резюме
Ще разработим мобилно приложение под ключ
IT Sectr създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.
Прочетете също