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.
Този тръбопроводен подход позволява гъвкаво комбиниране на плъгини: можете да инсталирате 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 г. Ще ви консултираме и ще предложим най-доброто решение.
Прочетете също