Ktor è un client HTTP asincrono per Kotlin, sviluppato da JetBrains come parte dell'omonimo framework per lo sviluppo server e client. Ktor è costruito sulle coroutine Kotlin e supporta il multipiattaforma. Secondo JetBrains, 2025, Ktor fornisce un'integrazione nativa con l'ecosistema Kotlin senza riflessione e dipendenze aggiuntive.
Punti chiave
Ktor è un framework per costruire applicazioni asincrone server e client in Kotlin, creato da JetBrains. Ktor Client è la parte client del framework, che fornisce un client HTTP con supporto completo per le coroutine Kotlin, multipiattaforma (JVM, Native, JS) e un'architettura modulare basata su plugin.
Ktor è emerso nel 2018 come alternativa a Retrofit e OkHttp per progetti Kotlin-first. A differenza di Retrofit, che ha portato l'approccio Java con annotazioni, Ktor Client utilizza Kotlin DSL per la configurazione delle richieste — senza annotazioni e riflessione. Questo rende il codice più leggibile e type-safe per gli sviluppatori Kotlin.
Secondo il sondaggio Kotlin Multiplatform 2024, Ktor Client è utilizzato nel 35% dei progetti Kotlin Multiplatform Mobile (KMM), rendendolo il secondo client HTTP più popolare dopo OkHttp nella comunità Kotlin. Ktor è preferito in progetti dove il supporto multipiattaforma e l'integrazione nativa con l'ecosistema Kotlin sono importanti.
L'architettura di Ktor Client si basa su una pipeline di plugin. Ogni richiesta attraversa una sequenza di plugin installati che possono modificare la richiesta, la risposta o eseguire azioni secondarie — logging, compressione, serializzazione, autenticazione.
Quando si crea un client HTTP tramite il blocco DSL HttpClient { }, si specifica il motore (OkHttp, Android, CIO, Darwin) e si installano i plugin. Ogni motore implementa l'invio di richieste di basso livello per una piattaforma specifica: su Android viene utilizzato il motore OkHttp, su iOS — Darwin (URLSession), su Desktop — CIO (Coroutine I/O). HttpClient seleziona automaticamente il motore ottimale per la piattaforma corrente.
Una richiesta in Ktor Client viene eseguita tramite una funzione suspend, che significa integrazione completa con le coroutine. Nessun Callback, nessun RxJava o LiveData — solo codice sequenziale con suspend che funziona in modo asincrono senza bloccare il thread.
La pipeline di Ktor è composta da fasi: prima la richiesta attraversa i plugin installati (es. ContentNegotiation per JSON, Logging per i log), poi il motore esegue la richiesta HTTP, e la risposta attraversa nuovamente i plugin per la deserializzazione. Ogni plugin è una funzione suspend che si esegue nella coroutine della pipeline.
Un importante vantaggio della pipeline di Ktor è la capacità di eseguire elaborazione condizionale. Un plugin può verificare l'URL o le intestazioni della richiesta e saltare l'elaborazione se la condizione non è soddisfatta. Ad esempio, ContentEncoding con gzip viene applicato solo alle risposte contenenti l'intestazione Content-Encoding: gzip, e Auth si attiva solo per gli endpoint protetti senza influenzare le API pubbliche.
Questo approccio a pipeline consente di combinare i plugin in modo flessibile: è possibile installare ContentNegotiation con JSON, aggiungere Auth con token Bearer, abilitare la compressione ContentEncoding e HttpTimeout — e tutti funzioneranno insieme nell'ordine corretto. L'ordine di installazione dei plugin è importante: il primo plugin installato elaborerà la richiesta prima degli altri.
I plugin sono il sistema di estensione modulare di Ktor, che sostituisce le annotazioni di Retrofit e gli interceptor di OkHttp. Ogni plugin risolve un compito specifico e viene installato tramite la funzione install() nel blocco HttpClient. Ktor fornisce plugin integrati e consente anche di crearne di personalizzati.
| Plugin | Scopo |
|---|---|
| ContentNegotiation | Serializzazione e deserializzazione JSON, XML tramite Kotlinx Serialization |
| Logging | Registrazione di richieste e risposte con livello configurabile |
| Auth | Autenticazione: Basic, Bearer, Digest con aggiornamento automatico del token |
| HttpTimeout | Configurazione dei timeout di connessione, lettura e richiesta |
| ContentEncoding | Compressione trasparente gzip e deflate |
| DefaultRequest | Impostazione dei valori predefiniti per tutte le richieste |
Per compiti specifici, viene creato un plugin personalizzato tramite createClientPlugin. Il plugin può intercettare la richiesta (onRequest), la risposta (onResponse) o gestire gli errori (onError). Questo sostituisce completamente l'Interceptor di OkHttp, ma con un'API Kotlin tipizzata e supporto per funzioni suspend.
I plugin personalizzati sono utili per aggiungere metriche, logica di ripetizione automatica, tracciamento delle richieste o test A/B degli endpoint. A differenza degli interceptor di OkHttp, i plugin Ktor sono scritti in Kotlin e vengono eseguiti nel contesto della coroutine, semplificando la gestione degli errori e dei timeout.
Per il debug delle richieste, viene utilizzato il plugin Logging con livello ALL, HEADERS o BODY. Logging restituisce il metodo, URL, stato, intestazioni e corpo della richiesta e risposta. A differenza di HttpLoggingInterceptor di OkHttp, Ktor Logging funziona in modo asincrono e può essere configurato per filtrare per livello di log (ERROR, WARN, INFO, DEBUG) senza fermare l'applicazione per modificare la configurazione.
Esaminiamo una richiesta GET di base con Ktor Client. Viene creato un HttpClient con il plugin ContentNegotiation installato per JSON. La richiesta viene eseguita tramite la funzione suspend get(), e il risultato viene automaticamente deserializzato in una 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()
}
Per una richiesta POST con corpo, viene utilizzata la funzione post() con contentType() e body(). Ktor serializza automaticamente l'oggetto in JSON tramite ContentNegotiation installato. Lo stile DSL rende il codice sequenziale e leggibile.
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 e DefaultRequest sono due plugin chiave per la configurazione. HttpTimeout imposta i limiti di tempo, e DefaultRequest specifica intestazioni e parametri URL per tutte le richieste, eliminando la duplicazione di codice in ogni chiamata.
val client = HttpClient {
install(HttpTimeout) {
connectTimeoutMillis = 15000
requestTimeoutMillis = 30000
}
install(DefaultRequest) {
url("https://api.github.com/")
header("Accept", "application/json")
}
}
Il multipiattaforma è il principale vantaggio di Ktor rispetto a OkHttp e Retrofit. Ktor Client funziona su JVM (Android, Server), Native (iOS, macOS, Windows, Linux) e JS (Browser). Lo stesso codice client HTTP viene eseguito su tutte le piattaforme senza modifiche, il che è particolarmente prezioso per i progetti Kotlin Multiplatform.
Per ogni piattaforma, Ktor utilizza il proprio motore. Su Android, viene utilizzato di default il motore OkHttp, che offre piena compatibilità con l'ecosistema OkHttp. Su iOS viene utilizzato DarwinEngine, basato su URLSession. Per Server — CIOEngine (Coroutine I/O). Il motore può essere specificato esplicitamente: HttpClient(OkHttp) { } o HttpClient(Darwin) { }.
Quando si sceglie un motore, considerare le sue capacità: il motore OkHttp supporta HTTP/2 e il pooling di connessioni, DarwinEngine offre integrazione nativa di rete iOS e sessioni URLSession in background, CIOEngine è un'implementazione pura di coroutine senza dipendenze esterne. Per i target Web, viene utilizzato JsEngine o BrowserEngine, che funziona tramite fetch API.
Grazie a un'API unificata su tutte le piattaforme, il codice per caricare i dati appare uguale su Android, iOS e Desktop. Questo riduce la duplicazione del codice del 60–80% nei progetti KMM rispetto a implementazioni separate su Retrofit (Android) e URLSession (iOS). Anche i plugin funzionano su tutte le piattaforme senza modifiche.
Ignorare la chiusura di HttpClient è un errore comune in Ktor. HttpClient implementa Closeable e deve essere chiuso al termine dell'applicazione tramite client.close(). In Android, ciò viene fatto in onDestroy() dell'Activity o ViewModel.onCleared(). Un client non chiuso porta a perdite di coroutine e thread del motore.
Ordine errato dei plugin può rompere l'elaborazione delle richieste. Ad esempio, ContentNegotiation dovrebbe essere installato prima di DefaultRequest affinché il tipo di contenuto venga applicato correttamente. Si consiglia di installare Logging per ultimo per registrare la versione finale della richiesta dopo tutte le modifiche. Sperimentate l'ordine se i plugin si comportano in modo inaspettato.
Mancata gestione delle eccezioni nelle funzioni suspend. Ktor genera IOException per errori di rete e ClientRequestException per stati HTTP 4xx. Il blocco try-catch è obbligatorio per ogni chiamata a get(), post() e altri metodi. Utilizzare HttpResponseValidator nel blocco HttpClient per la gestione globale degli errori senza duplicare try-catch in ogni metodo.
Domande frequenti
Ktor utilizza Kotlin DSL e plugin senza annotazioni e riflessione. Retrofit è costruito su annotazioni Java e riflessione. Ktor supporta il multipiattaforma, Retrofit solo JVM/Android. Ktor funziona nativamente con le coroutine, Retrofit ha aggiunto suspend tramite un wrapper.
Per Android, il motore OkHttp è ottimale — offre compatibilità con l'ecosistema OkHttp, pooling di connessioni, caching e HTTP/2. Sceglietelo tramite HttpClient(OkHttp) { }. L'alternativa è CIOEngine, integrato in Ktor, ma è meno stabile su Android.
Sì, Ktor supporta HTTP/2 tramite il motore appropriato. Il motore OkHttp eredita il supporto HTTP/2 da OkHttp. DarwinEngine su iOS supporta HTTP/2 tramite URLSession. CIOEngine supporta HTTP/2 sul lato server. La scelta del motore determina il livello di supporto del protocollo.
Utilizzare il plugin Auth con configurazione bearer { }. Il plugin aggiunge automaticamente l'intestazione Authorization a ogni richiesta e può aggiornare il token su risposta 401 tramite refreshTokens. Esempio: install(Auth) { bearer { loadTokens { BearerTokens(token, refreshToken) } } }.
Sì, Ktor Client funziona completamente su iOS tramite DarwinEngine, che utilizza URLSession. Tutti i plugin, la serializzazione e le coroutine funzionano su iOS come su Android. Questo rende Ktor il client HTTP principale per i progetti Kotlin Multiplatform Mobile (KMM).
Riepilogo
Svilupperemo un'applicazione mobile chiavi in mano
IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.
Leggi anche