Long Polling vs WebSocket dans Kotlin : que choisir pour le temps réel
\n\nImaginez : vous écrivez un chat en Kotlin, un terminal boursier ou un système de surveillance de serveurs. Le client doit voir les changements instantanément. La requête HTTP traditionnelle « aller-retour » ne convient pas ici — les données doivent arriver d'elles-mêmes, sans sollicitations constantes de l'utilisateur.
\n\nDans le monde de Kotlin, il existe deux approches populaires : Long Polling et WebSocket. Toutes deux permettent d'organiser une interaction en temps réel, mais le font de manière fondamentalement différente. Laquelle choisir ? Analysons cela avec des exemples concrets, sans blabla ni cours académiques.
\n\nQu'est-ce que le Long Polling (et pourquoi il n'est pas mort)
\n\nLong Polling est une technique où le client envoie une requête HTTP, et le serveur ne répond pas immédiatement, mais « reste en attente » jusqu'à l'arrivée de nouvelles données. Dès que les données arrivent — le serveur envoie une réponse, le client la traite et ouvre immédiatement une nouvelle requête. Le cycle se répète.
\n\nCela ressemble à du HTTP classique, mais avec un long délai d'attente. Aucun protocole supplémentaire, aucune poignée de main — tout fonctionne sur du HTTP/1.1 ou HTTP/2 standard.
\n\nExemple de Long Polling en Kotlin (Ktor Server + OkHttp Client)
\n\nPartie serveur avec Ktor (le serveur attendra jusqu'à ce qu'un message apparaisse) :
\n\nimport io.ktor.server.engine.*\nimport io.ktor.server.netty.*\nimport io.ktor.server.routing.*\nimport io.ktor.server.response.*\nimport io.ktor.http.*\nimport kotlinx.coroutines.*\n\nfun main() {\n embeddedServer(Netty, port = 8080) {\n routing {\n get("/long-poll") {\n // Simulation d'attente d'un nouveau message\n val message = withContext(Dispatchers.Default) {\n delay(5000) // attend 5 secondes (ou un nouvel événement)\n "Nouveau message : ${System.currentTimeMillis()}"\n }\n call.respondText(message, ContentType.Text.Plain)\n }\n }\n }.start(wait = true)\n}\n\n\nClient avec OkHttp :
\n\nimport okhttp3.*\n\nval client = OkHttpClient.Builder()\n .readTimeout(30, TimeUnit.SECONDS) // point important !\n .build()\n\nfun startLongPolling() {\n val request = Request.Builder()\n .url("http://localhost:8080/long-poll")\n .build()\n\n client.newCall(request).enqueue(object : Callback {\n override fun onFailure(call: Call, e: IOException) {\n e.printStackTrace()\n // Redémarrer obligatoirement le polling en cas d'erreur\n startLongPolling()\n }\n\n override fun onResponse(call: Call, response: Response) {\n response.use {\n if (response.isSuccessful) {\n println("Reçu : ${response.body?.string()}")\n // Lancer immédiatement la requête suivante\n startLongPolling()\n }\n }\n }\n })\n}\n\n\nAvantages du Long Polling :
\n- \n
- Fonctionne partout, même derrière des proxys d'entreprise et dans les anciens navigateurs \n
- Débogage simple — vous voyez des requêtes HTTP classiques dans les logs \n
- S'intègre facilement dans l'infrastructure existante (équilibreurs de charge, caches, CDN) \n
Inconvénients :
\n- \n
- Latence élevée — entre l'envoi de la requête et la réception de la réponse, un RTT (Round Trip Time) peut s'écouler \n
- Le serveur maintient de nombreuses connexions ouvertes (chaque requête est un thread/coroutine séparé) \n
- Lors de la reconnexion, une perte de messages est possible (si l'idempotence n'est pas implémentée) \n
WebSocket : un duplex complet
\n\nWebSocket est un protocole distinct (ws://) qui établit une connexion bidirectionnelle permanente après une poignée de main HTTP. Le serveur et le client peuvent envoyer des messages à tout moment, sans surcharge d'en-têtes.
\n\n