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 побудована на ланцюзі перехоплювачів. Кожний запит проходить через послідовність перехоплювачів, які можуть модифікувати запит, відповідь або перервати виконання. Ця архітектура нагадує патерн Chain of Responsibility і дозволяє гнучко розширювати функціонал.
Коли додаток надсилає запит, OkHttp виконує такі кроки: вирішує DNS, обирає з’єднання з пулу (або створює нове), відкриває TLS-рукопотиск (якщо HTTPS), надсилає HTTP-запит, отримує відповідь та повертає її додатку. RealCall — це внутрішній клас, який керує повним життєвим циклом запиту від створення до завершення.
OkHttp автоматично обробляє перенаправлення (302, 301), повторює запити при збоях мережі, дотримується протоколу keep-alive та підтримує прозоре стиснення gzip. Розробнику не потрібно писати код для цих операцій — OkHttp робить їх автоматично на основі заголовків сервера.
HTTP/2 дозволяє надсилати кілька запитів через одне TCP-з’єднання одночасно, без блокування head-of-line (властивого для HTTP/1.1). OkHttp автоматично використовує HTTP/2, якщо сервер підтримує цей протокол, і прозоро перемикається на HTTP/1.1 при необхідності.
Мультиплексування HTTP/2 особливо важливе для мобільних додатків, де затримка встановлення з’єднання (TCP + TLS) може становити 100–300 мс. Замість 10 послідовних з’єднань OkHttp використовує одне, знижуючи загальну затримку на 40–60% на типових Android-пристроях з нестабільним з’єднанням.
Interceptor — це інтерфейс з єдиним методом intercept(Chain), який отримує запит, виконує дії та повертає відповідь. Існують два типи перехоплювачів: прикладні (додаються через addInterceptor) та мережеві (addNetworkInterceptor).
Прикладні перехоплювачі спрацьовують до формування HTTP-запиту — вони бачать оригінальний запит та фінальну відповідь після всіх перетворень. Мережеві перехоплювачі спрацьовують на рівні мережі: вони бачать запит після стиснення gzip, додавання заголовка Content-Length, перенаправлень та повторних спроб. Мережеві перехоплювачі не викликаються, якщо відповідь отримано з кешу.
| Тип перехоплювача | Метод додавання | Коли викликається | Бачить кеш |
|---|---|---|---|
| Application Interceptor | addInterceptor() | До та після запиту | Так |
| Network Interceptor | addNetworkInterceptor() | На мережевому рівні | Ні |
На практиці перехоплювачі OkHttp вирішують три основні завдання: авторизація (додавання заголовка Authorization), логування (HttpLoggingInterceptor для налагодження) та повторна спроба (автоматичне повторення запиту при збоях мережі). Комбінуючи кілька перехоплювачів, можна побудувати повний конвеєр обробки запитів без дублювання коду в кожному 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 виконує запит у фоновому потоці та повертає результат у зворотному виклику на тому ж потоці. Для перемикання на головний потік 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 раунди), що додає 100–500 мс до кожного запиту.
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 для прив’язки сертифікатів, 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 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.