Node.js Server-Sent Events
Willemers Informatik-Ecke
Normalerweise fragt der Client den Server und erhält daraufhin eine Antwort, oft in Form von HTML-Daten. Die Kommunikationsrichtung ist eindeutig. Der Client meldet sich, wenn er etwas will. Der Server schläft, bis er geweckt wird.

In manchen Fällen will der Server aber den Clients mit freudigen Nachrichten überhäufen. Das muss dann von langer Hand vorbereitet werden. Der Server bereitet einen Event-Stream vor, den der Client im JavaScript seiner Webseite entgegen nimmt, die Ereignisse erwartet und bei Eintreffen verarbeitet. Der Content-Type eines solchen Streams heißt "text/event-stream".

Der Server

Wird der Server über localhost:8080 angesprochen, sendet er erst einmal eine HTML-Datei zu, die sich um die Events kümmern wird.

Ansonsten wartet er auf eine Anfrage der Clientseite, die vereinbarungsgemäß über die URL /sendtoclient oder einem anderen frei gewählten Namen erfolgt. Wichtiger ist, dass es sich um einen "text/event-stream" Inhalt handelt.

Dann antwortet der Server mit dem Einverständnis und fordert das Aufrechterhalten einer Verbindung ohne Cache.

Das Intervall wird im Beispiel auf 1000 Millisekunden gesetzt und jedes Mal soll die Funktion sendeTick aufgerufen werden. Diese sendet über die response ein Datenpaket mit Daten. Hier der Einfachheit halber eine Zahl, die sich bei jedem Aufruf erhöht.

const server = http.createServer( function(request, response) {
    if (request.headers.accept
    && request.headers.accept === "text/event-stream"
    && request.url === "/sendtoclient") {
        response.writeHead(200, {
                "Content-Type" : "text/event-stream",
                "Cache-Control": "no-cache",
                "Connection"   : "keep-alive", });
        setInterval( function() {
            sendeTick(response);
        }, 1000); // Intervall: eine Sekunde
    } else {
        // sende HTML-Seite mit JavaScript für Server-Send
        sendHtml("eventhandler.html", response);
    }
});
server.listen(8080);

let zahl = 0;

function sendeTick(response) {
    zahl = zahl + 1;
    response.write("data: "+zahl+"\n\n");
}

Der Event-Handler im HTML

Die HTML-Datei benötigt einen JavaScript-Teil, der sich um den Empfang der Server-Nachrichten kümmert. Dieser meldet sich mit EventSource an dem Pfad an und meldet eine eigene Funktion für die Bearbeitung einer eintreffenden Nachricht an.

Das EventSource-Interface ermöglicht es dem Client, auf Ereignisse des Content-Type "text/event-stream" zu reagieren. Ein Event hat die Attribute event, data, id und retry.

Im Beispiel wird die vom Server gesendete Zahl empfangen und in einer ul nach und nach angezeigt. In diesem Fall muss nur ein Teil der HTML-Datei manipuliert werden und nicht eine komplette Seite neu geladen werden, wie das bei der üblichen Kommunikationsrichtung erforderlich wäre.

<html>
<body>
<script>
const source = new EventSource('/sendtoclient');
source.onmessage = function(event) {
    let newElement = document.createElement("li");
    newElement.textContent = event.data;
    let ul = document.querySelector("#zaehler")
    ul.appendChild(newElement)
};
</script>
<h1>Wir zählen ... </h1>
<ul id="zaehler"></ul>
</body>
</html>

Links