Quand tu utilises un chat en ligne, WhatsApp Web, Slack ou Discord, les messages
des autres apparaissent sur ton écran sans que tu aies besoin de rafraîchir la page.
Pourtant, le protocole HTTP vu dans les chapitres
précédents ne fonctionne pas comme ça. HTTP repose sur un modèle de requête et
de réponse, le client demande, le serveur répond, et l'échange s'arrête là.
Le serveur n'a aucun moyen de prendre l'initiative d'envoyer quelque chose
au client, tout simplement parce qu'il ne sait pas comment le joindre.
Comment faire alors pour que le serveur puisse pousser des informations
en temps réel ? Trois réponses techniques existent, et elles cohabitent toujours.
Le polling, la solution naïve
La première approche s'appelle le polling, ou interrogation périodique.
Le client envoie une requête au serveur toutes les X secondes pour vérifier
s'il y a du nouveau.
"Hey serveur, j'ai de nouveaux messages ?" Non.
"Hey serveur, j'ai de nouveaux messages ?" Non.
"Hey serveur, j'ai de nouveaux messages ?" Oui, en voilà un.
C'est simple, ça marche partout, et ça reste parfaitement acceptable pour
beaucoup de besoins. Mais le gaspillage est évident, l'immense majorité
des requêtes ne rapportent rien tout en consommant de la bande passante
et du temps serveur. Sur mobile, ce bavardage permanent vide aussi la batterie.
Et il subsiste toujours un délai entre l'événement réel et sa détection,
qui vaut en moyenne la moitié de l'intervalle choisi.
Une variante astucieuse existe, le long polling. Le client pose sa question,
et au lieu de répondre "non" immédiatement, le serveur garde la requête ouverte
jusqu'à ce qu'il ait effectivement quelque chose à annoncer, ou qu'un délai
maximum expire. Le client relance aussitôt une nouvelle requête. On obtient
un quasi temps réel sans rien changer à l'infrastructure, au prix de connexions
maintenues ouvertes en permanence côté serveur. C'est la technique qui a fait
tourner les premiers chats web, et elle sert encore de solution de repli
quand rien d'autre ne passe.
Le WebSocket, une connexion permanente
Le WebSocket, standardisé en 2011, résout le problème d'une autre manière,
en établissant une connexion bidirectionnelle permanente entre le client
et le serveur.
Au lieu du modèle "je demande, tu réponds, on se quitte", le WebSocket ouvre
un canal qui reste ouvert. Le client et le serveur peuvent s'envoyer des messages
à tout moment, dans les deux sens, sans rétablir quoi que ce soit.
C'est la différence entre s'écrire des lettres et décrocher le téléphone.
Le plus élégant, c'est la façon dont la connexion démarre. Le client envoie
une requête HTTP tout à fait ordinaire, avec un en-tête qui demande poliment
de changer de protocole. Si le serveur est d'accord, il répond avec le
code HTTP 101, "Switching Protocols",
et la même connexion réseau bascule alors en WebSocket. Cette poignée de main
initiale en HTTP est ce qui permet au WebSocket de traverser les pare-feux
et les infrastructures web existantes, là où un protocole complètement
à part aurait été bloqué partout.
Tu croiseras deux adresses, ws:// pour une connexion en clair
et wss:// pour une connexion chiffrée. En production,
seule la seconde est acceptable, exactement comme HTTPS a remplacé HTTP.
Les cas d'usage
Le WebSocket est présent partout où le temps réel compte vraiment.
- Le chat : Slack, Discord, WhatsApp Web. Les messages arrivent instantanément, et l'indicateur "untel est en train d'écrire" n'existerait pas sans canal permanent.
- Les notifications en direct : les alertes qui apparaissent dans une messagerie ou un réseau social sans recharger la page.
- Les jeux en ligne : chaque mouvement d'un joueur doit être transmis aux autres en quelques dizaines de millisecondes. Attention, ça vaut surtout pour les jeux de navigateur et les jeux au tour par tour. Les jeux d'action très nerveux, eux, préfèrent UDP, qui accepte de perdre un message plutôt que d'attendre qu'on le renvoie.
- La collaboration en temps réel : Google Docs, Figma. Plusieurs personnes travaillent sur le même document et voient les modifications des autres, curseur compris, au fil de la frappe.
- Les données financières : les cours de bourse qui se mettent à jour en continu, où un prix vieux de quelques secondes n'a déjà plus aucune valeur.
- Le suivi de position : le livreur ou le chauffeur dont tu vois l'icône se déplacer sur la carte.
Server-Sent Events, le compromis
Il existe une solution intermédiaire, les Server-Sent Events, ou SSE.
Comme avec le WebSocket, le serveur peut pousser des données vers le client
sans que celui-ci les demande. La différence tient à ce que la communication
est unidirectionnelle, seul le serveur émet. Si le client a quelque chose
à dire, il fait une requête HTTP classique à côté.
En échange de cette limitation, SSE apporte de vrais avantages. Il reste
du HTTP ordinaire, donc il traverse sans difficulté les proxys et les caches
d'entreprise qui bloquent parfois le WebSocket. Il gère tout seul la reconnexion
automatique quand le réseau coupe, ce qu'il faut coder soi-même en WebSocket.
Et il est nettement plus simple à mettre en oeuvre côté serveur.
C'est largement suffisant pour un flux de notifications, la mise à jour
d'un tableau de bord, une barre de progression d'export, ou le streaming
de réponses d'une intelligence artificielle. C'est d'ailleurs ce mécanisme
qui fait apparaître les réponses de ChatGPT ou de Claude mot par mot
plutôt que d'un bloc.
Ne confonds pas tout ça avec les webhooks, qui répondent à un besoin voisin mais entre serveurs. Là, c'est ton serveur qui expose une adresse, et le service tiers vient l'appeler quand un événement survient, par exemple un paiement validé. Le principe du "ne m'appelle pas, je t'appellerai" est le même, mais il n'y a aucun navigateur dans l'histoire et aucune connexion maintenue.
Ce que ça coûte côté technique
Le temps réel n'est pas gratuit, et c'est utile de le savoir avant de le demander.
Une connexion permanente immobilise des ressources sur le serveur pendant toute
sa durée, même quand rien ne circule. Dix mille utilisateurs connectés, ce sont
dix mille connexions ouvertes à maintenir. C'est parfaitement faisable,
mais cela se dimensionne et se surveille.
Plus subtil, une connexion WebSocket est rattachée à un serveur précis.
Si ton infrastructure répartit le trafic sur plusieurs machines, deux utilisateurs
du même salon de discussion peuvent se retrouver sur des serveurs différents,
qui ne savent rien l'un de l'autre. Il faut alors un mécanisme pour faire
circuler les messages entre eux, typiquement une
file de messages. C'est le vrai
chantier d'un projet temps réel, bien plus que l'ouverture de la connexion.
Enfin, les connexions se coupent. Passage du Wi-Fi à la 5G, tunnel, mise en veille
du téléphone, coupure par un équipement réseau qui juge la connexion inactive.
Une application sérieuse envoie donc régulièrement un petit signal de vie
pour maintenir le canal, détecte les ruptures, se reconnecte automatiquement
et rattrape les messages manqués pendant la coupure. Des bibliothèques
comme Socket.IO existent précisément pour prendre en charge cette plomberie,
avec un repli sur le long polling quand le WebSocket est bloqué.
Que choisir
La règle est assez simple, et elle va du moins cher au plus cher.
Le polling suffit dès qu'un délai de quelques secondes ou quelques dizaines
de secondes est acceptable, et il ne demande aucune infrastructure particulière.
SSE s'impose quand seul le serveur a des choses à annoncer, ce qui couvre
la majorité des besoins de notification et de tableau de bord.
Le WebSocket devient justifié quand les deux parties doivent parler
en permanence et vite, chat, collaboration, jeu.
De mon expérience, l'erreur la plus courante consiste à choisir le WebSocket
par principe, parce que c'est la solution la plus moderne, pour un besoin
qu'un rafraîchissement toutes les trente secondes aurait réglé. On hérite
alors de toute la complexité de reconnexion et de répartition, sans aucun
bénéfice pour l'utilisateur. Demande toujours quel délai est réellement
inacceptable pour le métier avant de choisir la technique.