Chapitre 10 : HTML5 – Server-Sent Events (SSE)

📖 1. Introduction aux Server-Sent Events

Les Server-Sent Events (SSE) permettent au serveur d'envoyer des mises à jour automatiques au client (navigation web) via une connexion HTTP persistante.

❌ Polling (avant SSE)

  • Requêtes répétitives
  • Latence élevée
  • Surcharge réseau importante

✅ SSE

  • Communication unidirectionnelle serveur → client
  • Faible latence
  • Reconnexion automatique
  • Basé sur HTTP/HTTPS

Temps réel

Notifications instantanées

🔄

Auto-reconnexion

Gérée nativement par le navigateur

🔌

Facile à utiliser

API simple sur navigateur

📦

Léger

Format texte simple (text/event-stream)

💡 Différence avec WebSocket : SSE est unidirectionnel (serveur → client) tandis que WebSocket est bidirectionnel (client ↔ serveur). SSE est plus simple pour des flux de données comme les notifications, actualités, scores sportifs.

🌐 2. Support navigateurs

🌐

Chrome

✅ Supporté
🦊

Firefox

✅ Supporté
🧭

Safari

✅ Supporté
🌍

Edge

✅ Supporté

Opera

✅ Supporté
// Détection du support SSE
if (typeof(EventSource) !== "undefined") {
    console.log("SSE est supporté");
    // Créer une connexion SSE
    const source = new EventSource("sse.php");
} else {
    console.log("SSE n'est pas supporté");
    // Fallback: utiliser le polling
}

💻 3. Client Web Application

Côté client, l'API EventSource permet de se connecter au flux SSE.

// Créer une connexion SSE
const source = new EventSource('chemin/vers/le/script-sse');

// Écouter les messages
source.onmessage = function(event) {
    console.log('Message reçu:', event.data);
    // Mettre à jour l'interface utilisateur
    document.getElementById('notifications').innerHTML += '<p>' + event.data + '</p>';
};

// Gestion des erreurs
source.onerror = function(event) {
    console.log('Erreur de connexion SSE');
};

📝 Démo : Client SSE (simulation)

✨ Simulation de connexion SSE

🖥️ 4. Server Side Script

Côté serveur, le script doit envoyer les données au format text/event-stream.

<?php
// sse.php - Exemple PHP
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
header('Access-Control-Allow-Origin: *');

while(true) {
    $time = date('H:i:s');
    echo "data: Le serveur est actif à {$time}\n\n";
    flush();
    sleep(2);
}
?>
📌 Format du flux SSE
  • data: message\n\n – Message standard
  • event: nom\n – Spécifie le type d'événement
  • id: 123\n – ID du message
  • retry: 3000\n – Temps de reconnexion (ms)
💡 Remarque : Les scripts SSE doivent s'exécuter en boucle infinie et envoyer régulièrement des données.

📡 5. Gestion des événements

onopen

Déclenché lorsque la connexion est établie

source.onopen = () => console.log('Connecté');
onmessage

Déclenché à chaque réception de message

source.onmessage = (e) => console.log(e.data);
onerror

Déclenché en cas d'erreur (réseau, serveur)

source.onerror = () => console.log('Erreur');
const source = new EventSource('sse.php');

source.onopen = function() {
    console.log('Connexion SSE établie');
    document.getElementById('status').innerHTML = '🟢 Connecté';
};

source.onmessage = function(event) {
    console.log('Données:', event.data);
    updateUI(event.data);
};

source.onerror = function(event) {
    console.error('Erreur SSE');
    document.getElementById('status').innerHTML = '🔴 Erreur de connexion';
};

🏷️ 6. Événements nommés

Il est possible de définir plusieurs types d'événements.

<?php
// Côté serveur (PHP)
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');

while(true) {
    // Envoi d'un événement "news"
    echo "event: news\n";
    echo "data: Nouvelle actualité importante !\n\n";
    
    // Envoi d'un événement "weather"
    echo "event: weather\n";
    echo "data: Température: 22°C\n\n";
    
    flush();
    sleep(5);
}
?>
// Côté client
const source = new EventSource('sse.php');

// Écouter l'événement 'news'
source.addEventListener('news', function(event) {
    console.log('Actualité:', event.data);
});

// Écouter l'événement 'weather'
source.addEventListener('weather', function(event) {
    console.log('Météo:', event.data);
});

📝 Démo : Événements nommés

✨ Simulation d'événements nommés

🔄 7. Reconnexion automatique

Le navigateur tente automatiquement de se reconnecter si la connexion est perdue.

<?php
// Côté serveur : contrôler le délai de reconnexion
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');

// Définir le délai de reconnexion (5 secondes)
echo "retry: 5000\n\n";

while(true) {
    echo "data: Message périodique\n\n";
    flush();
    sleep(10);
}
?>
📌 Comportement
  • Si la connexion est interrompue, le navigateur tente de se reconnecter
  • Le délai par défaut est de 3 secondes
  • La directive retry: X permet de modifier ce délai (en millisecondes)
  • La reconnexion est automatique, pas besoin de code supplémentaire

🔌 8. Fermeture de la connexion

Pour fermer manuellement une connexion SSE, utilisez la méthode close().

let source = null;

// Démarrer la connexion
function startSSE() {
    source = new EventSource('sse.php');
    source.onmessage = function(event) {
        console.log(event.data);
    };
}

// Fermer la connexion
function stopSSE() {
    if (source) {
        source.close();
        console.log('Connexion SSE fermée');
        source = null;
    }
}
💡 Astuce : Il est important de fermer les connexions SSE lorsque vous naviguez hors de la page pour éviter les fuites mémoire.

📝 9. Exemple complet : Flux d'actualités

<!DOCTYPE html>
<html>
<head>
    <title>Flux d'actualités en temps réel</title>
    <style>
        body { font-family: Arial, sans-serif; max-width: 800px; margin: 0 auto; padding: 20px; }
        .news-item { background: #f8f9fa; border-left: 4px solid #3498db; padding: 10px; margin: 10px 0; }
        .time { color: #666; font-size: 0.8em; }
        #status { padding: 8px; border-radius: 6px; margin-bottom: 15px; }
        .connected { background: #d4edda; color: #155724; }
        .error { background: #f8d7da; color: #721c24; }
    </style>
</head>
<body>
    <h1>📰 Flux d'actualités en temps réel</h1>
    <div id="status">🟡 Connexion en cours...</div>
    <div id="news"></div>

    <script>
        let eventSource = null;
        const newsDiv = document.getElementById('news');
        const statusDiv = document.getElementById('status');
        
        function startSSE() {
            if (eventSource) eventSource.close();
            
            eventSource = new EventSource('news.php');
            
            eventSource.onopen = function() {
                statusDiv.className = 'connected';
                statusDiv.innerHTML = '🟢 Connecté - En attente d\'actualités...';
            };
            
            eventSource.onmessage = function(event) {
                const data = JSON.parse(event.data);
                const newsItem = document.createElement('div');
                newsItem.className = 'news-item';
                newsItem.innerHTML = `
                    <div><strong>${data.title}</strong></div>
                    <p>${data.content}</p>
                    <div class="time">${new Date().toLocaleTimeString()}</div>
                `;
                newsDiv.insertBefore(newsItem, newsDiv.firstChild);
                
                // Garder seulement les 20 dernières actualités
                while(newsDiv.children.length > 20) {
                    newsDiv.removeChild(newsDiv.lastChild);
                }
            };
            
            eventSource.onerror = function() {
                statusDiv.className = 'error';
                statusDiv.innerHTML = '🔴 Erreur de connexion - Reconnexion automatique...';
            };
        }
        
        startSSE();
        
        // Fermer la connexion en quittant la page
        window.addEventListener('beforeunload', function() {
            if (eventSource) eventSource.close();
        });
    </script>
</body>
</html>

📝 Démo : Flux d'actualités simulé

✨ Simulation de flux SSE complet
🟢 Connecté - Réception des notifications

📝 Tableau récapitulatif

Objet/Méthode Description Exemple
new EventSource(url) Crée une connexion SSE new EventSource('stream.php')
onopen Événement de connexion établie source.onopen = () => {...}
onmessage Réception d'un message source.onmessage = (e) => {...}
onerror Erreur de connexion source.onerror = () => {...}
addEventListener() Écouter un événement nommé source.addEventListener('news', fn)
close() Ferme la connexion source.close()

📌 Quiz de vérification

Question 1 : Quelle est la différence principale entre SSE et WebSocket ?
✅ Réponse

SSE est unidirectionnel (serveur → client), WebSocket est bidirectionnel (client ↔ serveur). SSE est plus simple pour des flux de données comme les notifications.

Question 2 : Comment créer une connexion SSE côté client ?
✅ Réponse

const source = new EventSource('url_du_script_sse');

Question 3 : Quelle en-tête HTTP est obligatoire pour un script SSE ?
✅ Réponse

Content-Type: text/event-stream

Question 4 : Que se passe-t-il si la connexion SSE est interrompue ?
✅ Réponse

Le navigateur tente automatiquement de se reconnecter, avec un délai configurable via la directive retry.