HTML5: Einführung in Server-Sent Events

Ein Schattendasein hinter der HTML5 WebSocket-Technologie führt die auch im Rahmen von HTML5 spezifizierte Server-Sent Events (SSEs)-Technik.

Dabei handelt es sich um eine reine Server-Push-Technik bei der der Webbrowser eine unidirektionale HTTP-Verbindung zum Server offen hält.

Über die offene Verbindung kann der Server jederzeit Nachrichten an den Client schicken, ohne dass die Verbindung wie z. B. beim Long-Polling zwischendurch getrennt und wieder neu hergetellt werden muss. Wobei hier angemerkt werden muss, dass auch klassisches Polling hiermit durchaus möglich ist.

In diesem Beitrag möchte ich euch nun zeigen, wie ihr HTML5 Server-Sent Events einsetzen bzw. implementieren könnt.

Clientseitige Implementierung

Die clientseitige Implementierung ist analog zu der HTML5 WebSockets-Implementierung sehr einfach gehalten und durch die WHATWG spezifiziert. Dazu mal folgender JavaScript-Code als Beispiel:

var eventSource;

if(!!window.EventSource)
{
    eventSource = new EventSource('my-event-source.php');
} else {
    alert('Dein Browser untestützt keine HTML5 Server-Sent Events');
}

eventSource.addEventListener('open', function(event)
{
    console.log('Verbindung wurde erfolgreich hergestellt.');
});

eventSource.addEventListener('message', function(event)
{
    console.log('Nachricht: ' + event.data);
});

eventSource.addEventListener('error', function(event)
{
    if (event.readyState === EventSource.CLOSED)
    {
        console.log('Fehler aufgetreten - die Verbindung wurde getrennt.');
    }
});
JavaScript

Wir machen nichts weiter als erst zu überprüfen, ob HTML5 Server-Sent Events vom verwendeten Webbrowser unterstützt werden (Zeile 3 - 8). Dazu nutzen wir einfach eine doppelte Negation.

Anschließend werden die Event-Handler definiert. Wenn die Verbindung zum Server erfolgreich hegestellt wurde, dann wird der open-Event-Handler gefeuert und dessen angegebene Callback-Methode ausgeführt (Zeile 10 - 13).

In unseren Fall lassen wir uns die Verbindungsherstellung in der Konsole ausgeben. Analog arbeitet der onmessage- bzw. onerror-Event-Handler (Zeile 15 - 26).

Bei einer eingehenden Nachricht, die der Server gesendet hat, ist diese über das event-Objekt mittels der data-Eigenschaft abrufbar.

Serverseitige Implementierung

Auf Serverseite kann nun ein Skript z. B. unendlich ausgeführt werden, um ständig aktuelle Daten zum Client zu schicken. Wichtig ist, dass der Server die Nachricht mittels dem Content-Type text/event-stream überträgt.

Dazu solltet man noch angeben, dass kein Caching seitens des Webbrowsers stattfinden soll. Dazu folgendes PHP-Beispiel:

header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');

while(true)
{
    echo "data: " . (new DateTime())->format('d.m.Y - H:i:s') . "\n\n";
    ob_flush();
    flush();
    sleep(1);
}
PHP

Wir haben hier eine unendliche Schleife, die uns immer die aktuelle Server-Zeit zum Client schickt. Die Sinnhaftigkeit dessen sei jetzt hier mal dahingestellt, aber das Beipsiel soll euch ja nur zeigen, wie einfach die serverseitige Implementierung ist.

Außerdem ist anzumerken, dass jede Nachricht mit dem Präfix data: eingeleitet wird. Anschließend wird der eigentliche Text der Nachricht angegeben und abgeschlossen wird die Nachricht mit einer Newline-Sequenz (\n\n).

Weiterhin ist zu beachten, dass wenn das Server-Skript endlich ist, wird am Ende der Ausführung die Verbindung getrennt. Jedoch stellt der Webbrowser standardmäßig nach einigen Sekunden (je nach Webbrowser-Implementierung kann das verschieden sein) die Verbindung wieder her und das Skript wird erneut ausgeführt.

Das oben gezeige Server-Skript würde also auch ohne die while-Schleife funktionieren und uns immer alle paar Sekunden die aktuelle Serverzeit zum Client senden.

Zeit für erneutes Verbinden des Webbrowsers ändern

Wenn das Server-Skript endlich ist, verbindet sich der Webbrowser, wie bereits eben erwähnt, nach etwa 3 Sekunden wieder mit dem Server. Diese Zeit können wir aber auch mit retry ändern:

header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');

echo "retry: 10000\n" .
     "data: " . (new DateTime())->format('d.m.Y - H:i:s') . "\n\n";
flush();
PHP

Dabei wird die Zeit in Millisekunden angegeben. In diesem konkreten Beispiel wird die Server-Zeit nun nur noch alle 10 Sekunden an den Client geschickt, weil sich der Webbrowser erst nach 10 Sekunden wieder mit dem Server verbindet.

Individuelle Events festlegen

Eine weitere Funktionalität beim Einsatz von HTML5 Server-Sent Events ist, dass wir individuelle Events festlegen können, auf dir wir mit einem eigenen Event-Handler unterschiedlich reagieren können.

Dazu können wir serverseitig mittels event: eine Nachricht einem bestimmten Event zuordnen:

header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');

echo "event: servertime\n" .
     "data: " . (new DateTime())->format('d.m.Y - H:i:s') . "\n\n";
flush();
PHP

Nun können wir clientseitig einen neuen Event-Handler definieren, der immer bei eintreffenden servertime-Events ausgelöst wird. Dazu ergänzen wir unseren clientseitigen JavaScript-Code und fügen Folgendes hinzu:

eventSource.addEventListener('servertime', function(event)
{
    console.log('Serverzeit: ' + event.data);
});
JavaScript

Durch die Möglichkeit eigene Events zu definieren, ist es ein Leichtes auf unterschiedliche Nachrichtentypen individuell zu reagieren.

Webbrowser-Unterstützung

HTML5 Server-Sent Events werden derzeit in allen gängigen Webbrowsern, mit Ausnahme des Internet Explorers unterstützt.

Den aktuellen Stand zur Webbrowser-Kompatibilität findet ihr hier: caniuse.com

Fazit

Wie ihr sehen könnt, lässt sich die Technik der HTML5 Server-Sent Events sowohl auf Client- als auch Serverseite relativ leicht umsetzen. Damit kann es als sinnvolle AJAX-Alternative verwendet werden, wenn es darum geht, dass der Client nicht ständig Daten zum Server senden muss, sondern der Fokus darauf liegt, dass der Client nur Updates vom Server erhält.

Im Gegensatz zu HTML5 WebSockets benötigt ihr kein spezifisches Protokoll und auch keine spezielle serverseitige Implementierung. Des Weiteren besticht die Server-Sent Events-Technik durch sinnvolle Funktionen, wie z.B. dem Wiederverbinden bei zusammengebrochenen Verbindungen und der Möglichkeit Event-IDs zu vergeben und somit individuell auf verschiedene Events reagieren zu können.

Aktualisierungshistorie:
  • 28. August 2012
    ursprüngliche Veröffentlichung in meinem ehemaligen Blog "Smart-Webentwicklung"
Feedback

Für Feedback zum Beitrag, seien es Fragen, Korrigierungen und/oder Anregungen, könnt ihr mir gerne eine Nachricht per E-Mail oder Mastodon schreiben (siehe Kontakt).