Introduction
Server-Sent Events (SSE) est un standard web natif pour des communications unidirectionnelles du serveur vers le client en temps réel. Contrairement aux WebSockets (bidirectionnels), SSE est plus simple à implémenter : pas de gestion de trames complexes, reconnexion automatique, et support natif dans tous les navigateurs modernes.
Pourquoi l'utiliser en 2026 ? Pour des notifications live (nouveaux messages, alertes), mises à jour de dashboards (stats en temps réel), ou suivi de tâches longues sans recharger la page. C'est léger (texte brut via HTTP), scalable (connexions persistantes gérées par le navigateur), et évite le polling coûteux en ressources.
Ce tutoriel beginner vous guide pas à pas : du serveur Node.js basique à un client robuste avec reconnexion. À la fin, vous aurez un exemple fonctionnel copié-collable pour des événements personnalisés et données JSON. Temps estimé : 15 minutes.
Prérequis
- Node.js 20+ installé
- Connaissances basiques en JavaScript (variables, fonctions, async)
- Un éditeur de code (VS Code recommandé)
- Navigateur moderne (Chrome, Firefox)
Initialiser le projet et installer les dépendances
mkdir sse-tutorial
cd sse-tutorial
npm init -y
npm install express corsCe script crée un dossier projet, initialise package.json et installe Express pour le serveur HTTP, ainsi que CORS pour autoriser les requêtes cross-origin depuis le client. Lancez-le dans votre terminal pour un setup prêt en 30 secondes.
Comprendre les bases de SSE
SSE utilise un flux text/event-stream sur une connexion HTTP persistante. Le serveur envoie des messages au format data: message\n\n. Le client, via EventSource, écoute et parse automatiquement. Avantage : reconnexion auto après 3s si déconnexion.
Créer le serveur SSE basique
const express = require('express');
const cors = require('cors');
const app = express();
app.use(cors());
app.get('/events', (req, res) => {
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
'Access-Control-Allow-Origin': '*'
});
let counter = 0;
const interval = setInterval(() => {
counter++;
res.write(`data: Compteur: ${counter}\n\n`);
}, 1000);
req.on('close', () => {
clearInterval(interval);
res.end();
});
});
app.listen(3000, () => {
console.log('Serveur SSE sur http://localhost:3000');
});Ce serveur expose /events comme endpoint SSE. Il envoie un compteur incrémenté toutes les secondes. Les headers obligatoires activent le flux persistant ; req.on('close') nettoie l'intervalle pour éviter les fuites mémoire. Lancez avec node server.js.
Créer le client HTML simple
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<title>SSE Client</title>
</head>
<body>
<h1>Server-Sent Events Demo</h1>
<div id="messages"></div>
<script>
const eventSource = new EventSource('http://localhost:3000/events');
const messagesDiv = document.getElementById('messages');
eventSource.onmessage = (event) => {
const newMessage = document.createElement('p');
newMessage.textContent = event.data;
messagesDiv.appendChild(newMessage);
};
eventSource.onerror = (error) => {
console.error('Erreur SSE:', error);
};
</script>
</body>
</html>Ce fichier HTML autonome connecte à /events via EventSource. onmessage affiche chaque data reçue. onerror log les erreurs (reconnexion auto gérée par le navigateur). Ouvrez-le dans un navigateur pour voir le compteur live.
Tester la démo basique
- Lancez
node server.js. - Ouvrez
index.htmldans votre navigateur. - Observez les messages arriver toutes les secondes. Fermez/réouvrez l'onglet : reconnexion auto !
Ajouter des événements personnalisés
const express = require('express');
const cors = require('cors');
const app = express();
app.use(cors());
app.get('/events', (req, res) => {
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
'Access-Control-Allow-Origin': '*'
});
let counter = 0;
const interval = setInterval(() => {
counter++;
if (counter % 5 === 0) {
res.write(`event: alerte\ndata: Alerte niveau ${counter}!\n\n`);
} else {
res.write(`data: Compteur normal: ${counter}\n\n`);
}
}, 1000);
req.on('close', () => {
clearInterval(interval);
res.end();
});
});
app.listen(3000, () => {
console.log('Serveur SSE sur http://localhost:3000');
});Amélioration : utilise event: nom pour typer les messages (ex: 'alerte'). Tous les 5 ticks, un événement spécial est envoyé. Cela permet de filtrer côté client. Remplacez l'ancien server.js et relancez.
Client avancé avec gestion d'événements et JSON
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<title>SSE Client Avancé</title>
</head>
<body>
<h1>SSE avec Événements Personnalisés</h1>
<div id="normal"></div>
<div id="alertes"></div>
<script>
const eventSource = new EventSource('http://localhost:3000/events');
const normalDiv = document.getElementById('normal');
const alertesDiv = document.getElementById('alertes');
eventSource.addEventListener('alerte', (event) => {
const data = JSON.parse(event.data);
const alertDiv = document.createElement('div');
alertDiv.style.color = 'red';
alertDiv.textContent = `ALERTE: ${data.message}`;
alertesDiv.appendChild(alertDiv);
});
eventSource.onmessage = (event) => {
const p = document.createElement('p');
p.textContent = event.data;
normalDiv.appendChild(p);
};
eventSource.onerror = () => {
console.log('Reconnexion en cours...');
};
</script>
</body>
</html>Client filtre les événements via addEventListener('alerte'). Parse JSON pour données structurées. onerror gère gracieusement les déconnexions. Remplacez index.html ; maintenant, alertes en rouge !
Serveur avec données JSON dynamiques
const express = require('express');
const cors = require('cors');
const app = express();
app.use(cors());
let usersOnline = 0;
app.get('/events', (req, res) => {
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
'Access-Control-Allow-Origin': '*'
});
const interval = setInterval(() => {
usersOnline += Math.floor(Math.random() * 3) - 1;
if (usersOnline < 0) usersOnline = 0;
const data = { users: usersOnline, timestamp: Date.now() };
res.write(`data: ${JSON.stringify(data)}\n\n`);
}, 2000);
req.on('close', () => {
clearInterval(interval);
res.end();
});
});
app.listen(3000, () => {
console.log('Serveur SSE JSON sur http://localhost:3000');
});Maintenant, envoie des objets JSON simulés (utilisateurs en ligne). Idéal pour dashboards réels. Le client précédent les parse automatiquement. Cela illustre des données complexes sans changer le protocole SSE.
Bonnes pratiques
- Toujours cleaner les intervalles/timers sur
req.closepour éviter les leaks. - Limitez les reconnexions :
new EventSource(url, { heartbeatTimeout: 30000 }). - Utilisez ID pour resume :
id: ${timestamp}\ncôté serveur, géré auto par client. - Bufférisez les petits messages pour réduire la latence réseau.
- Scalez avec Redis pour shared state multi-instances.
Erreurs courantes à éviter
- Oublier 'Connection: keep-alive' : la connexion ferme après un message.
- Ne pas gérer CORS : erreurs cross-origin bloquent le client.
- Envoyer sans
\n\nfinal : messages non parsés par EventSource. - Ignorer les multiples clients : utilisez un broadcaster comme ioredis pour scaler.
Pour aller plus loin
- Docs MDN : Server-Sent Events
- Implémentez avec React : hooks
useEffectpour EventSource. - Comparez à WebSockets pour bidirectionnel.
- Découvrez nos formations Learni sur le temps réel : Node.js avancé, WebSockets pro.