Server-Sent Events en TypeScript : streaming de données sans maux de tête
\n\nImaginez : votre serveur génère des données — logs, notifications, mises à jour des taux de change — et doit les envoyer instantanément au frontend. WebSocket ? Puissant, mais excessif. Polling ? Lent et consomme de la bande passante. Il existe une troisième voie, élégante, simple et incroyablement utile : les Server-Sent Events (SSE).
\n\nDans cet article, nous allons décortiquer les SSE en TypeScript de A à Z. Nous écrirons un client et un serveur, apprendrons à gérer les erreurs et les reconnexions, et surtout, nous comprendrons quand les SSE sont vraiment avantageux par rapport aux autres approches. C'est parti !
\n\nQue sont les Server-Sent Events et pourquoi en avez-vous besoin ?
\n\nLes Server-Sent Events sont une norme HTML5 qui permet au serveur d'envoyer des données au client via une seule connexion HTTP en temps réel. Contrairement à WebSocket, les SSE sont unidirectionnels : seul le serveur envoie des messages. Mais c'est précisément là leur force — ils sont extrêmement simples et ne nécessitent aucune bibliothèque supplémentaire.
\n\nQuand choisir les SSE ?
\n\n- \n
- Streaming unidirectionnel : notifications, logs, taux de change, tickers boursiers. \n
- Intégration simple : fonctionne via le
EventSourcestandard du navigateur — aucun paquet npm nécessaire. \n - Reconnexion automatique : le navigateur rétablit lui-même la connexion en cas de rupture. \n
- Compatibilité avec HTTP/2 : le multiplexage ne pose pas de problème, contrairement à WebSocket. \n
Mais rappelez-vous : les SSE ne peuvent pas envoyer de données du client vers le serveur (utilisez des requêtes POST classiques pour cela) et ne sont pas pris en charge dans les anciens navigateurs (IE — bonjour).
\n\nPartie serveur : écrire des SSE en TypeScript + Express
\n\nCommençons par le backend. Créons un serveur simple avec Node.js, Express et TypeScript. Installez les dépendances :
\n\nnpm init -y\nnpm install express cors\nnpm install -D typescript @types/express @types/node ts-node\nnpx tsc --init\n\nÉcrivons maintenant le serveur lui-même. Le point clé est de définir les bons en-têtes et le format des messages.
\n\n// server.ts\nimport express, { Request, Response } from 'express';\nimport cors from 'cors';\n\nconst app = express();\napp.use(cors());\n\n// Endpoint pour SSE\napp.get('/events', (req: Request, res: Response) => {\n // Définition des en-têtes pour SSE\n res.writeHead(200, {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n 'Connection': 'keep-alive',\n });\n\n // Envoi d'un message initial\n res.write('data: {"message": "Connexion établie"}\\n\\n');\n\n // Envoi d'un événement toutes les 3 secondes\n const intervalId = setInterval(() => {\n const data = JSON.stringify({\n time: new Date().toISOString(),\n value: Math.random() * 100,\n });\n res.write(`data: ${data}\\n\\n`);\n }, 3000);\n\n // Gestion de la déconnexion du client\n req.on('close', () => {\n clearInterval(intervalId);\n res.end();\n console.log('Client déconnecté');\n });\n});\n\nconst PORT = 3000;\napp.listen(PORT, () => console.log(`Serveur SSE démarré sur le port ${PORT}`));\n\nNotez le format : chaque message commence par data: et se termine par deux sauts de ligne \\n\\n. Vous pouvez également spécifier id, event et retry — mais c'est la base.
Envoi d'événements nommés
\n\nParfois, il est nécessaire de distinguer les types de messages. Ajoutons le champ event :
res.write('event: update\\n');\nres.write(`data: ${JSON.stringify({ id: 1, title: 'Nouvel article' })}\\n\\n`);\n\n// Puis un autre événement\nres.write('event: notification\\n');\nres.write('data: {"level": "info", "text": "Le serveur fonctionne"}\\n\\n');\n\nSur le client, nous pourrons nous abonner à des événements spécifiques.
\n\nPartie cliente : réception des événements en TypeScript
\n\nÉcrivons maintenant le client. Dans le navigateur, on utilise le EventSource intégré. Mais si