OkHttp è un client HTTP ad alte prestazioni per Android e Kotlin, sviluppato da Square come base per Retrofit e altre librerie di rete. Fornisce una gestione efficiente delle connessioni, memorizzazione nella cache integrata e supporto HTTP/2. Secondo Square, 2025, OkHttp gestisce miliardi di richieste al giorno in applicazioni in tutto il mondo.
Punti chiave
OkHttp è un client HTTP efficiente per Java, Android e Kotlin, sviluppato da Square. La libreria fornisce un’API di basso livello per eseguire richieste HTTP con supporto per HTTP/2, SPDY, WebSocket e ripristino automatico della connessione in caso di guasti di rete.
OkHttp è nato nel 2013 in risposta alla necessità di un client HTTP affidabile che risolvesse i problemi di HttpURLConnection — mancanza di pool di connessioni, scarso supporto HTTP/2 e API scomoda. Entro il 2025, OkHttp viene utilizzato a livello di sistema nell’Android API: OkHttp è integrato nell’implementazione di HttpURLConnection a partire da Android 4.4 (API 19).
Secondo Google I/O 2024, OkHttp gestisce oltre il 70% di tutte le richieste HTTP nell’ecosistema Android. Ciò è possibile perché OkHttp funge da livello di trasporto per Retrofit, Apollo GraphQL, Firebase e molte altre librerie. Gli sviluppatori ottengono le funzionalità di OkHttp automaticamente senza doverlo aggiungere esplicitamente.
L’architettura di OkHttp è costruita su una catena di interceptor. Ogni richiesta attraversa una sequenza di interceptor che possono modificare la Request, la Response o interrompere l’esecuzione. Questa architettura ricorda il pattern Chain of Responsibility e consente un’estensibilità flessibile.
Quando un’applicazione invia una richiesta, OkHttp esegue i seguenti passaggi: risolve il DNS, seleziona una connessione dal pool (o ne crea una nuova), apre un handshake TLS (se HTTPS), invia la richiesta HTTP, riceve la risposta e la restituisce all’applicazione. RealCall è la classe interna che gestisce l’intero ciclo di vita di una richiesta dalla creazione al completamento.
OkHttp gestisce automaticamente i reindirizzamenti (302, 301), ripete le richieste in caso di guasti di rete, segue il protocollo keep-alive e supporta la compressione gzip trasparente. Lo sviluppatore non deve scrivere codice per queste operazioni — OkHttp le esegue automaticamente in base alle intestazioni del server.
HTTP/2 consente di inviare più richieste contemporaneamente su una singola connessione TCP, senza blocco head-of-line (caratteristico di HTTP/1.1). OkHttp utilizza automaticamente HTTP/2 se il server lo supporta e passa in modo trasparente a HTTP/1.1 quando necessario.
Il multiplexing HTTP/2 è particolarmente importante per le applicazioni mobili, dove la latenza di configurazione della connessione (TCP + TLS) può essere di 100–300 ms. Invece di 10 connessioni sequenziali, OkHttp ne usa una, riducendo la latenza totale del 40–60% sui tipici dispositivi Android con connessioni instabili.
Interceptor è un’interfaccia con un singolo metodo intercept(Chain), che riceve una Request, esegue azioni e restituisce una Response. Esistono due tipi di interceptor: interceptor di applicazione (aggiunti tramite addInterceptor) e interceptor di rete (addNetworkInterceptor).
Gli interceptor di applicazione si attivano prima della formazione della richiesta HTTP — vedono la Request originale e la Response finale dopo tutte le trasformazioni. Gli interceptor di rete si attivano a livello di rete: vedono la richiesta dopo la compressione gzip, l’aggiunta dell’intestazione Content-Length, i reindirizzamenti e i tentativi. Gli interceptor di rete non vengono chiamati se la risposta viene servita dalla cache.
| Tipo di interceptor | Metodo di aggiunta | Quando viene chiamato | Vede la cache |
|---|---|---|---|
| Application Interceptor | addInterceptor() | Prima e dopo la richiesta | Sì |
| Network Interceptor | addNetworkInterceptor() | A livello di rete | No |
In pratica, gli interceptor di OkHttp risolvono tre compiti principali: autorizzazione (aggiunta dell’intestazione Authorization), registrazione (HttpLoggingInterceptor per il debug) e ritentativo (ripetizione automatica della richiesta in caso di guasti di rete). Combinando più interceptor, è possibile costruire una pipeline completa di elaborazione delle richieste senza duplicare il codice in ogni chiamata HTTP dell’applicazione.
L’ordine di aggiunta degli interceptor è importante: l’Interceptor aggiunto per primo viene eseguito per primo all’ingresso e per ultimo all’uscita. Per NetworkInterceptor, l’ordine è determinato dallo stack di rete. Ordine consigliato: AuthInterceptor (aggiunge token), LoggingInterceptor (registra la richiesta), RetryInterceptor (ripete in caso di fallimento).
Per eseguire il debug delle richieste di rete, viene utilizzato HttpLoggingInterceptor — un interceptor pronto all’uso di Square. Registra il metodo, l’URL, le intestazioni e il corpo della richiesta e della risposta. Livelli di registrazione: BASIC (metodo + URL + codice), HEADERS (con intestazioni) e BODY (richiesta e risposta complete). BODY è utile durante lo sviluppo ma viene disabilitato in produzione per motivi di sicurezza e prestazioni.
Consideriamo una richiesta GET di base utilizzando OkHttp. Innanzitutto, viene creato un OkHttpClient — un oggetto pesante che viene creato una volta e riutilizzato. Quindi viene creata una Request con un URL e la richiesta viene eseguita in modo sincrono tramite execute o asincrono tramite 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())
Per l’esecuzione asincrona, viene utilizzato il metodo enqueue, che accetta un Callback. OkHttp esegue la richiesta in un thread in background e restituisce il risultato nel callback sullo stesso thread. Per passare al thread principale di Android, utilizzare Handler o coroutine.
client.newCall(request).enqueue(object : Callback {
override fun onFailure(
call: Call, e: IOException
) {
println("Richiesta fallita: ${e.message}")
}
override fun onResponse(
call: Call, response: Response
) {
println(response.body()?.string())
}
})
Un Interceptor personalizzato aggiunge un token Bearer a ogni richiesta. L’interceptor verifica la presenza dell’intestazione Authorization e, se il token non è ancora impostato, lo aggiunge dall’archivio. Su una risposta 401, l’interceptor può aggiornare il token tramite 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)
}
}
Pool di connessioni (ConnectionPool) è un‘ottimizzazione chiave di OkHttp che consente di riutilizzare le connessioni TCP per più richieste. Invece di creare un nuovo socket per ogni richiesta, OkHttp memorizza fino a 5 connessioni inattive (per impostazione predefinita) per 5 minuti, riducendo la latenza del 30–70% per le richieste ripetute allo stesso host.
La memorizzazione nella cache delle risposte viene implementata tramite la classe Cache. Per abilitare la cache, è sufficiente specificare la directory e la dimensione massima in OkHttpClient.Builder. OkHttp memorizza automaticamente nella cache le risposte GET secondo le intestazioni Cache-Control, Expires e ETag, restituendo i dati memorizzati nella cache senza richiesta di rete se non sono obsoleti.
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()
La corretta configurazione del pool e della cache è particolarmente importante per le applicazioni con richieste frequenti — feed di notizie, chat, aggiornamenti dei dati. Senza pool, ogni connessione TCP richiede un handshake a tre vie (SYN, SYN-ACK, ACK) e potenzialmente un handshake TLS (2–3 round trip), aggiungendo 100–500 ms a ogni richiesta.
OkHttp supporta anche WebSocket tramite la classe RealWebSocket. Una connessione WebSocket viene stabilita tramite un handshake HTTP (101 Switching Protocols) e poi passa a un protocollo bidirezionale. OkHttp invia automaticamente frame ping per mantenere attiva la connessione e si riconnette in caso di disconnessione. Il WebSocket di OkHttp è compatibile con endpoint standard come wss://echo.websocket.org.
Creare OkHttpClient per ogni richiesta è l’errore più comune. OkHttpClient contiene un pool di connessioni, cache e thread pool. Creare una nuova istanza per ogni richiesta non solo spreca memoria, ma perde anche il vantaggio del riutilizzo delle connessioni. OkHttpClient dovrebbe essere un singleton tramite un contenitore DI.
Ignorare la chiusura di Response.body() porta a perdite di risorse. ResponseBody contiene un InputStream che deve essere chiuso dopo la lettura. Se si utilizza body().string() o body().bytes(), OkHttp chiude automaticamente lo stream, ma durante la lettura di body().byteStream() o body().charStream(), è necessaria una chiamata esplicita a close() in un blocco finally.
Mancata gestione del Timeout è un altro problema. Per impostazione predefinita, OkHttp ha connectTimeout di 10 secondi, readTimeout di 10 secondi e writeTimeout di 10 secondi. Per le applicazioni mobili con connessioni instabili, si consiglia di impostare connectTimeout su 15–30 secondi e readTimeout su 15–30 secondi, altrimenti l’utente aspetterà troppo a lungo con un segnale debole.
Domande frequenti
OkHttp è un client HTTP di basso livello con gestione manuale di Request e Response. Retrofit è un’astrazione di alto livello con annotazioni. OkHttp viene utilizzato come livello di trasporto per Retrofit, ma può funzionare anche in modo indipendente senza librerie aggiuntive.
OkHttp utilizza SSLSocketFactory per l’handshake TLS. La libreria supporta CertificatePinner per il pinning dei certificati, TrustManager per la convalida personalizzata e HostnameVerifier per verificare il nome host rispetto al certificato.
Le richieste sincrone lanciano IOException in caso di problemi di rete. Le richieste asincrone ricevono una chiamata onFailure con IOException. Per gli errori HTTP (4xx, 5xx), la risposta è considerata riuscita — il codice di errore viene verificato tramite response.isSuccessful().
Sì, OkHttp ha il supporto integrato per WebSocket tramite la classe WebSocket e WebSocketListener. Dopo aver stabilito una connessione, WebSocket consente di inviare e ricevere messaggi in tempo reale senza richieste HTTP ripetute.
Disabilita i reindirizzamenti automatici tramite followRedirects(false) e followSslRedirects(false) in OkHttpClient.Builder. Ciò è utile quando è necessario gestire manualmente un reindirizzamento, ad esempio, per estrarre un token dall’URL di reindirizzamento.
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