OkHttp для Kotlin: полное руководство с примерами

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Что такое OkHttp и зачем он нужен?

OkHttp — это мощная и эффективная HTTP-библиотека для JVM (Java Virtual Machine), Android и Kotlin/Native, разработанная компанией Square. Она предоставляет удобный API для выполнения HTTP-запросов и обработки ответов. OkHttp является де-факто стандартом для работы с сетью в экосистеме Android и активно используется в серверных Kotlin-приложениях.

Зачем использовать OkHttp вместо стандартных средств Java (HttpURLConnection)?

  • Простота и удобство: Чистый, текучий (fluent) API, который легко читать и писать.
  • Производительность: Встроенная поддержка HTTP/2, автоматическое сжатие ответов (gzip), пул соединений (connection pooling) и кэширование.
  • Надёжность: Автоматические повторные запросы при сбоях сети, устойчивость к ошибкам DNS и TLS.
  • Гибкость: Легко настраиваемые перехватчики (interceptors) для логирования, аутентификации, модификации запросов и ответов.
  • Тестируемость: Возможность подменять сетевой слой с помощью MockWebServer.

OkHttp идеально подходит для Android-приложений, REST API-клиентов, микросервисов и любых других проектов на Kotlin, где требуется надёжная и быстрая работа с HTTP.

Установка

OkHttp распространяется через Maven Central. Для добавления в проект используйте систему сборки Gradle (наиболее распространённая для Kotlin).

Для Android / Kotlin/JVM проекта (build.gradle.kts):

dependencies {
    implementation("com.squareup.okhttp3:okhttp:4.12.0")
    // Для логирования (опционально)
    implementation("com.squareup.okhttp3:logging-interceptor:4.12.0")
}

Для Android / Kotlin/JVM проекта (build.gradle):

dependencies {
    implementation 'com.squareup.okhttp3:okhttp:4.12.0'
    implementation 'com.squareup.okhttp3:logging-interceptor:4.12.0'
}

Для Maven (pom.xml):

<dependency>
    <groupId>com.squareup.okhttp3</groupId>
    <artifactId>okhttp</artifactId>
    <version>4.12.0</version>
</dependency>

Важно: Убедитесь, что версия OkHttp совместима с вашей версией Kotlin. Актуальную версию всегда можно найти на MVNRepository.

Быстрый старт

Самый простой пример — выполнить GET-запрос и получить тело ответа в виде строки.

import okhttp3.OkHttpClient
import okhttp3.Request
import java.io.IOException

fun main() {
    // 1. Создаём клиент (обычно один на всё приложение)
    val client = OkHttpClient()

    // 2. Строим запрос
    val request = Request.Builder()
        .url("https://api.github.com/users/octocat")
        .build()

    // 3. Выполняем запрос синхронно (блокирует текущий поток)
    client.newCall(request).execute().use { response ->
        if (!response.isSuccessful) {
            throw IOException("Unexpected code $response")
        }
        // 4. Получаем тело ответа
        println(response.body?.string())
    }
}

Объяснение:

  1. OkHttpClient() — создаёт экземпляр клиента. Он потокобезопасен, поэтому рекомендуется создать один экземпляр и переиспользовать его.
  2. Request.Builder() — использует шаблон "Строитель" (Builder) для конфигурации запроса.
  3. client.newCall(request) — создаёт новый вызов (Call), который можно выполнить синхронно (execute()) или асинхронно (enqueue()).
  4. response.use { ... } — гарантирует, что ресурсы ответа (тело, соединение) будут закрыты после использования.
  5. response.body?.string() — читает тело ответа как строку. Важно: Тело можно прочитать только один раз!

Основные методы и функции

Рассмотрим ключевые методы OkHttp с подробными примерами.

1. OkHttpClient.Builder.build()

Что делает: Создаёт настроенный экземпляр OkHttpClient. Позволяет задать таймауты, перехватчики, кэш, прокси и другие параметры.

Параметры: Методы билдера (не все):

  • connectTimeout(Long, TimeUnit) — таймаут подключения.
  • readTimeout(Long, TimeUnit) — таймаут чтения данных.
  • writeTimeout(Long, TimeUnit) — таймаут записи данных.
  • addInterceptor(Interceptor) — добавляет перехватчик приложения.
  • addNetworkInterceptor(Interceptor) — добавляет сетевой перехватчик.
  • cache(Cache) — устанавливает кэш ответов.
  • proxy(Proxy) — настраивает прокси-сервер.

Пример:

val client = OkHttpClient.Builder()
    .connectTimeout(30, TimeUnit.SECONDS)
    .readTimeout(30, TimeUnit.SECONDS)
    .writeTimeout(30, TimeUnit.SECONDS)
    .addInterceptor(HttpLoggingInterceptor().apply {
        level = HttpLoggingInterceptor.Level.BODY
    })
    .build()

2. Request.Builder.url(String)

Что делает: Устанавливает URL для запроса. Может принимать строку или объект HttpUrl.

Параметры:

  • url: String — URL в виде строки.
  • url: HttpUrl — предварительно разобранный URL (позволяет безопасно добавлять параметры).

Пример:

// Строковый URL
val request1 = Request.Builder()
    .url("https://api.example.com/data")
    .build()

// Безопасный HttpUrl
val url = HttpUrl.Builder()
    .scheme("https")
    .host("api.example.com")
    .addPathSegment("data")
    .addQueryParameter("page", "1")
    .build()

val request2 = Request.Builder()
    .url(url)
    .build()

3. Request.Builder.header(String, String) и addHeader(String, String)

Что делает: Добавляет HTTP-заголовки к запросу. header() заменяет существующий заголовок, addHeader() добавляет новый, не удаляя старые.

Параметры:

  • name: String — имя заголовка.
  • value: String — значение заголовка.

Пример:

val request = Request.Builder()
    .url("https://api.example.com/secure")
    .header("Authorization", "Bearer token123")
    .addHeader("Accept", "application/json")
    .addHeader("User-Agent", "MyKotlinApp/1.0")
    .build()

4. Request.Builder.method(String, RequestBody?)

Что делает: Устанавливает HTTP-метод (GET, POST, PUT, DELETE, PATCH и т.д.) и тело запроса. Для методов без тела (GET, DELETE) тело должно быть null.

Параметры:

  • method: String — HTTP метод.
  • body: RequestBody? — тело запроса (может быть null).

Пример:

// POST с JSON телом
val json = MediaType.parse("application/json; charset=utf-8")
val body = RequestBody.create(json, """{"key": "value"}""")

val request = Request.Builder()
    .url("https://api.example.com/data")
    .method("POST", body)
    .build()

// GET запрос (тело не требуется)
val getRequest = Request.Builder()
    .url("https://api.example.com/data")
    .method("GET", null)
    .build()

5. Call.execute()

Что делает: Выполняет запрос синхронно. Блокирует текущий поток до получения ответа. Возвращает Response.

Параметры: Нет.

Возвращает: Response.

Исключения: IOException при сетевых ошибках.

Пример:

val client = OkHttpClient()
val request = Request.Builder().url("https://httpbin.org/get").build()

try {
    val response = client.newCall(request).execute()
    if (response.isSuccessful) {
        println(response.body?.string())
    }
} catch (e: IOException) {
    e.printStackTrace()
}

6. Call.enqueue(Callback)

Что делает: Выполняет запрос асинхронно в фоновом потоке. Не блокирует вызывающий поток. Результат приходит в колбэк.

Параметры:

  • callback: Callback — объект с двумя методами: onFailure(Call, IOException) и onResponse(Call, Response).

Пример:

val client = OkHttpClient()
val request = Request.Builder().url("https://httpbin.org/delay/2").build()

client.newCall(request).enqueue(object : Callback {
    override fun onFailure(call: Call, e: IOException) {
        println("Ошибка: ${e.message}")
    }

    override fun onResponse(call: Call, response: Response) {
        response.use {
            if (response.isSuccessful) {
                println("Успех: ${response.body?.string()}")
            }
        }
    }
})

// Не блокирует главный поток
println("Запрос отправлен асинхронно")

7. Response.isSuccessful

Что делает: Проверяет, является ли код ответа успешным (в диапазоне 200-299). Удобная альтернатива проверке response.code() in 200..299.

Параметры: Нет (свойство).

Возвращает: Boolean.

Пример:

val response = client.newCall(request).execute()
if (response.isSuccessful) {
    // Обработка успешного ответа
} else {
    println("Ошибка: ${response.code()} - ${response.message()}")
}

8. Response.body() и ResponseBody.string()

Что делает: response.body() возвращает объект ResponseBody, содержащий тело ответа. ResponseBody.string() читает тело как строку. Важно: Тело можно прочитать только один раз, после чего оно будет закрыто.

Параметры: Нет.

Возвращает: ResponseBody? (может быть null для ответов без тела, например 204 No Content).

Пример:

val response = client.newCall(request).execute()
val body = response.body

// Чтение как строка
val bodyString = body?.string()
println(bodyString)

// Чтение как байты
val bytes = body?.bytes()

// Чтение как поток
val inputStream = body?.byteStream()
inputStream?.use { stream ->
    // Чтение потока
}

9. ResponseBody.contentType()

Что делает: Возвращает MediaType

Рекомендаций