Ktor — это асинхронный HTTP-клиент для Kotlin, разработанный компанией JetBrains как часть одноимённого фреймворка для серверной и клиентской разработки. Ktor построен на корутинах Kotlin и поддерживает мультиплатформенность. По данным JetBrains, 2025, Ktor обеспечивает нативную интеграцию с Kotlin-экосистемой без рефлексии и дополнительных зависимостей.
Главное
Ktor — это фреймворк для построения асинхронных серверных и клиентских приложений на Kotlin, созданный компанией JetBrains. Ktor Client — клиентская часть фреймворка, предоставляющая HTTP-клиент с полной поддержкой корутин Kotlin, мультиплатформенности (JVM, Native, JS) и модульной архитектуры на плагинах.
Ktor появился в 2018 году как альтернатива Retrofit и OkHttp для Kotlin-first проектов. В отличие от Retrofit, который портировал Java-подход с аннотациями, Ktor Client использует Kotlin DSL для конфигурации запросов — без аннотаций и рефлексии. Это делает код более читаемым и типобезопасным для Kotlin-разработчиков.
По данным опроса Kotlin Multiplatform 2024, Ktor Client используется в 35% проектов Kotlin Multiplatform Mobile (KMM), что делает его вторым по популярности HTTP-клиентом после OkHttp в Kotlin-сообществе. Ktor предпочитают в проектах, где важна мультиплатформенность и нативная интеграция с Kotlin-экосистемой.
Архитектура Ktor Client основана на конвейере (pipeline) из плагинов. Каждый запрос проходит через последовательность установленных плагинов, которые могут модифицировать запрос, ответ или выполнять побочные действия — логирование, сжатие, сериализацию, аутентификацию.
При создании HTTP-клиента через HttpClient { } DSL-блоком вы указываете движок (OkHttp, Android, CIO, Darwin) и устанавливаете плагины. Каждый движок реализует низкоуровневую отправку запроса для конкретной платформы: на Android используется OkHttp-движок, на iOS — Darwin (URLSession), на Desktop — CIO (Coroutine-based I/O). HttpClient автоматически выбирает оптимальный движок для текущей платформы.
Запрос в Ktor Client выполняется через suspend-функцию, что означает полную интеграцию с корутинами. Никаких Callback, никаких RxJava или LiveData — только последовательный код с suspend, который работает асинхронно без блокировки потока.
Конвейер Ktor состоит из фаз: прежде всего запрос проходит через установленные плагины (например, ContentNegotiation для JSON, Logging для логов), затем движок выполняет HTTP-запрос, и ответ снова проходит через плагины для десериализации. Каждый плагин — это suspend-функция, выполняющаяся в корутине конвейера.
Важное преимущество конвейера Ktor — возможность условной обработки. Плагин может проверить URL или заголовки запроса и пропустить обработку, если условие не выполнено. Например, ContentEncoding с gzip применяется только к ответам, содержащим заголовок Content-Encoding: gzip, а Auth срабатывает только для защищённых эндпоинтов, не затрагивая публичные API.
Такой pipeline-подход позволяет комбинировать плагины гибко: вы можете установить ContentNegotiation с JSON, добавить Auth с Bearer-токеном, включить сжатие ContentEncoding и HttpTimeout — и все они будут работать совместно в правильном порядке. Порядок установки плагинов имеет значение: первый установленный будет обрабатывать запрос раньше остальных.
Плагины — это модульная система расширения Ktor, заменяющая аннотации Retrofit и перехватчики OkHttp. Каждый плагин решает конкретную задачу и устанавливается через функцию install() в блоке HttpClient. Ktor предоставляет встроенные плагины, а также позволяет создавать кастомные.
| Плагин | Назначение |
|---|---|
| ContentNegotiation | Сериализация и десериализация JSON, XML через Kotlinx Serialization |
| Logging | Логирование запросов и ответов с настройкой уровня |
| Auth | Аутентификация: Basic, Bearer, Digest с автоматическим обновлением токена |
| HttpTimeout | Настройка таймаутов подключения, чтения и запроса |
| ContentEncoding | Прозрачное сжатие gzip и deflate |
| DefaultRequest | Установка значений по умолчанию для всех запросов |
Для специфических задач создаётся кастомный плагин через createClientPlugin. Плагин может перехватывать запрос (onRequest), ответ (onResponse) или обрабатывать ошибки (onError). Это полностью заменяет Interceptor из OkHttp, но с типизированным Kotlin-API и поддержкой suspend-функций.
Кастомные плагины удобны для добавления метрик, автоматической ретрай-логики, трейсинга запросов или A/B-тестирования эндпоинтов. В отличие от перехватчиков OkHttp, Ktor-плагины написаны на Kotlin и работают в контексте корутины, что упрощает обработку ошибок и таймаутов.
Для отладки запросов используется плагин Logging с уровнем ALL, HEADERS или BODY. Logging выводит метод, URL, статус, заголовки и тело запроса и ответа. В отличие от HttpLoggingInterceptor из OkHttp, Ktor Logging работает асинхронно и может быть настроен на фильтрацию по уровню лога (ERROR, WARN, INFO, DEBUG) без остановки приложения для смены конфигурации.
Рассмотрим базовый GET-запрос через Ktor Client. Создаётся HttpClient с установленным плагином ContentNegotiation для JSON. Запрос выполняется через suspend-функцию get(), результат автоматически десериализуется в data class.
data class User(
val login: String,
val id: Int,
val avatarUrl: String
)
val client = HttpClient {
install(ContentNegotiation) {
json(Json {
ignoreUnknownKeys = true
})
}
}
suspend fun getUser(): User {
return client.get("https://api.github.com/users/octocat").body()
}
Для POST-запроса с телом используется функция post() с contentType() и body(). Ktor автоматически сериализует объект в JSON через установленный ContentNegotiation. DSL-стиль делает код последовательным и читаемым.
data class CreateRepo(
val name: String,
val description: String,
val private: Boolean
)
suspend fun createRepo(): Unit {
val repo = CreateRepo(
name = "my-project",
description = "Sample project",
private = false
)
client.post("https://api.github.com/user/repos") {
contentType(ContentType.Application.Json)
setBody(repo)
}
}
HttpTimeout и DefaultRequest — два ключевых плагина для конфигурации. HttpTimeout устанавливает лимиты времени, а DefaultRequest задаёт заголовки и параметры URL для всех запросов, избавляя от дублирования кода в каждом вызове.
val client = HttpClient {
install(HttpTimeout) {
connectTimeoutMillis = 15000
requestTimeoutMillis = 30000
}
install(DefaultRequest) {
url("https://api.github.com/")
header("Accept", "application/json")
}
}
Мультиплатформенность — главное преимущество Ktor перед OkHttp и Retrofit. Ktor Client работает на JVM (Android, Server), Native (iOS, macOS, Windows, Linux) и JS (Browser). Один и тот же код HTTP-клиента выполняется на всех платформах без изменений, что особенно ценно для Kotlin Multiplatform проектов.
Для каждой платформы Ktor использует свой движок (engine). На Android по умолчанию применяется OkHttp-движок, который даёт полную совместимость с OkHttp-экосистемой. На iOS используется DarwinEngine, основанный на URLSession. Для Server — CIOEngine (Coroutine I/O). Движок можно указать явно: HttpClient(OkHttp) { } или HttpClient(Darwin) { }.
При выборе движка учитывайте его возможности: OkHttp-движок поддерживает HTTP/2 и пул соединений, DarwinEngine — нативную интеграцию с iOS-сетью и фоновые сессии URLSession, CIOEngine — чистую корутинную реализацию без внешних зависимостей. Для Web-таргетов используется JsEngine или BrowserEngine, работающий через fetch API.
Благодаря единому API на всех платформах, код для загрузки данных выглядит одинаково на Android, iOS и Desktop. Это сокращает дублирование кода на 60–80% в KMM-проектах по сравнению с раздельными реализациями на Retrofit (Android) и URLSession (iOS). Плагины также работают на всех платформах без изменений.
Игнорирование закрытия HttpClient — частая ошибка в Ktor. HttpClient реализует Closeable, и его нужно закрывать при завершении работы приложения через client.close(). В Android это делается в onDestroy() Activity или ViewModel.onCleared(). Незакрытый клиент приводит к утечке корутин и потоков движка.
Неправильный порядок плагинов может сломать обработку запроса. Например, ContentNegotiation должен быть установлен до DefaultRequest, чтобы тип контента применялся корректно. Logging рекомендуется устанавливать последним, чтобы логировать финальную версию запроса после всех модификаций. Экспериментируйте с порядком, если плагины ведут себя неожиданно.
Отсутствие обработки исключений в suspend-функциях. Ktor выбрасывает исключения IOException при сетевых ошибках и ClientRequestException при HTTP-статусах 4xx. Блок try-catch обязателен для каждого вызова get(), post() и других методов. Используйте HttpResponseValidator в блоке HttpClient для глобальной обработки ошибок без дублирования try-catch в каждом методе.
Часто задаваемые вопросы
Ktor использует Kotlin DSL и плагины без аннотаций и рефлексии. Retrofit построен на Java-аннотациях и рефлексии. Ktor поддерживает мультиплатформенность, Retrofit — только JVM/Android. Ktor нативно работает с корутинами, Retrofit добавил suspend через обёртку.
Для Android оптимален OkHttp-движок — он обеспечивает совместимость с OkHttp-экосистемой, пул соединений, кэширование и HTTP/2. Выбирайте его через HttpClient(OkHttp) { }. Альтернатива — CIOEngine, встроенный в Ktor, но он менее стабилен на Android.
Да, Ktor поддерживает HTTP/2 через соответствующий движок. OkHttp-движок наследует поддержку HTTP/2 от OkHttp. DarwinEngine на iOS поддерживает HTTP/2 через URLSession. CIOEngine поддерживает HTTP/2 на серверной стороне. Выбор движка определяет уровень поддержки протокола.
Используйте плагин Auth с установкой bearer { }. Плагин автоматически добавляет заголовок Authorization к каждому запросу и может обновлять токен при ответе 401 через refreshTokens. Пример: install(Auth) { bearer { loadTokens { BearerTokens(token, refreshToken) } } }.
Да, Ktor Client полноценно работает на iOS через DarwinEngine, использующий URLSession. Все плагины, сериализация и корутины работают на iOS так же, как на Android. Это делает Ktor основным HTTP-клиентом для Kotlin Multiplatform Mobile (KMM) проектов.
Итоги
Мы разработаем мобильное приложение под ключ
IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.
Читайте также