Signatur
Beschreibung
Das message-Ereignis ist das Standard-Ereignis der EventSource-Schnittstelle für Server-Sent Events (SSE). Es wird immer dann ausgelöst, wenn der Server einen vollständigen Nachrichtenblock (abgeschlossen durch eine Leerzeile) sendet, der kein event:-Feld enthält oder ausdrücklich event: message angibt.
Der Handler erhält ein MessageEvent. Die wichtigsten Eigenschaften sind data (der Nachrichtentext als String; mehrere data:-Zeilen werden mit \n verbunden), lastEventId (Wert des letzten id:-Felds) und origin (Herkunft des Servers).
Registrieren lässt sich der Handler entweder per addEventListener("message", handler) (mehrere Handler möglich, entfernbar per removeEventListener) oder über die Eigenschaft onmessage (nur ein Handler, wird bei erneuter Zuweisung überschrieben). Typische Anwendungsfälle sind Live-Ticker, Benachrichtigungen, Fortschrittsanzeigen oder das Streamen von Log- bzw. KI-Antworten vom Server zum Client.
Wichtig: Nachrichten mit einem benannten Ereignistyp (z. B. event: update) lösen kein message-Ereignis aus. Dafür muss ein eigener Listener mit addEventListener("update", …) registriert werden.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $type Pflicht | string | Ereignisname, hier "message". |
|
| $handler Pflicht | (event: MessageEvent) => void | Callback, der für jede empfangene Standard-Nachricht mit einem MessageEvent aufgerufen wird. |
|
| $options | boolean | AddEventListenerOptions | false | Optionale Listener-Optionen wie once oder signal (zum Entfernen via AbortController). |
Rückgabewert
addEventListener gibt nichts zurück. Der Handler erhält ein MessageEvent mit data (string), lastEventId (string) und origin (string).Beispiele
Nachrichten per addEventListener empfangen und JSON parsen
const source = new EventSource('/api/stream');
source.addEventListener('message', (event) => {
// Server sendet z. B.: data: {"user":"Anna","text":"Hallo"}\n\n
try {
const msg = JSON.parse(event.data);
console.log(`${msg.user}: ${msg.text}`);
console.log('Letzte ID:', event.lastEventId);
} catch {
console.warn('Keine gültigen JSON-Daten:', event.data);
}
});
Alternative über die onmessage-Eigenschaft
const source = new EventSource('/api/ticker');
const list = document.querySelector('#ticker');
source.onmessage = (event) => {
const li = document.createElement('li');
li.textContent = event.data; // textContent statt innerHTML – XSS-sicher
list.prepend(li);
};
source.onerror = () => {
console.log('Verbindung unterbrochen, Browser versucht Reconnect …');
};
Listener wieder entfernen und Verbindung schließen
const source = new EventSource('/api/progress');
const onProgress = (event) => {
const percent = Number(event.data);
console.log(`Fortschritt: ${percent} %`);
if (percent >= 100) {
source.removeEventListener('message', onProgress);
source.close(); // verhindert automatische Neuverbindung
console.log('Fertig, Verbindung geschlossen.');
}
};
source.addEventListener('message', onProgress);
Standard- und benannte Ereignisse unterscheiden
const source = new EventSource('/api/events');
// Nur Nachrichten ohne 'event:'-Feld
source.addEventListener('message', (e) => console.log('Standard:', e.data));
// Nachricht mit 'event: alert' landet NICHT im message-Handler
source.addEventListener('alert', (e) => console.log('Alarm:', e.data));
// Wichtig · Fallstricke
- Benannte Ereignisse: Sendet der Server
event: xyz, wird keinmessage-Ereignis ausgelöst – ein häufiger Grund für „Handler feuert nie“. - Nur Text:
event.dataist immer ein String. Strukturierte Daten müssen mitJSON.parse()umgewandelt werden; Binärdaten werden nicht unterstützt. - Sicherheit: Empfangene Daten nie ungeprüft per
innerHTMLeinfügen (XSS). Bei Cross-Origin-Verbindungen muss der Server passende CORS-Header senden; Cookies nur mitnew EventSource(url, { withCredentials: true }). Die CSP-Direktiveconnect-srcmuss die Quelle erlauben. - Server-Anforderungen: Antwort mit
Content-Type: text/event-stream, jede Nachricht endet mit einer Leerzeile. Puffernde Proxys (z. B. nginx) können Nachrichten verzögern. - Verbindungslimit: Über HTTP/1.1 erlauben Browser nur ca. 6 gleichzeitige Verbindungen pro Domain (tabübergreifend); HTTP/2 löst das Problem.
- Kompatibilität: In allen modernen Browsern verfügbar, nicht im Internet Explorer. Auch in Web Workern nutzbar. Nicht standardmäßig in Node.js (erst experimentell ab Node.js 22).