WebSocket-Authentifizierung erklärt
WebSocket-Authentifizierung erklärt: Token in der URL, Cookies, Subprotokolle oder erstes Nachrichtensignal, plus Token-Erneuerung und Berechtigung pro Nachricht.
Die WebSocket-API des Browsers unterstützt keine benutzerdefinierten HTTP-Header — der WebSocket-Konstruktor akzeptiert ausschließlich eine URL und ein optionales Subprotokoll-Array — daher muss die Authentifizierung über einen von drei Mechanismen erfolgen: ein Token im Query-String während des HTTP-Upgrade-Handshakes, ein Session-Cookie, das der Browser automatisch sendet, oder ein Credential in der ersten Nachricht nach dem Verbindungsaufbau. Diese Einschränkung unterscheidet die WebSocket-Authentifizierung von der REST-Authentifizierung, bei der einfach ein Authorization: Bearer-Header an jede Anfrage angehängt wird.
Wer bereits REST-Authentifizierung mit JWTs oder Session-Cookies implementiert hat, kennt die einzelnen Bausteine. Was sich bei WebSockets ändert, sind der Übertragungsmechanismus und die Lebensdauer. Eine REST-Anfrage authentifiziert sich einmalig und endet. Eine WebSocket-Verbindung bleibt minutenlang oder stundenlang offen — das bedeutet, dass ein Token, der zum Zeitpunkt des Handshakes gültig war, ablaufen, widerrufen werden oder seine Berechtigungen verlieren kann, während der Socket noch geöffnet ist. Dieser Artikel behandelt jedes Handshake- und First-Message-Muster mit funktionsfähigem Browser- und Node.js-Code, liefert eine Entscheidungsregel zur Auswahl des richtigen Ansatzes und geht auf zwei Aspekte ein, die die meisten Anleitungen überspringen: Token-Erneuerung bei langlebigen Verbindungen und nachrichtenbasierte Autorisierung.
Wichtigste Erkenntnisse
- Der
WebSocket-Konstruktor des Browsers akzeptiert ausschließlich eine URL und ein Subprotokoll-Array, sodass keinAuthorization-Header gesendet werden kann — die Authentifizierung verlagert sich in den Query-String, ein Cookie, denSec-WebSocket-Protocol-Header oder die erste Nachricht. - WebSocket-Authentifizierung ist ein fortlaufender Kontrollmechanismus, kein einmaliges Ereignis: Da Verbindungen langlebig sind, sind nachrichtenbasierte Autorisierung und Token-Erneuerung produktive Anforderungen und keine optionale Härtungsmaßnahme.
- Verwenden Sie In-Band-Token-Aktualisierung, wenn der Socket zustandsbehaftete Subscriptions trägt; verwenden Sie Close-and-Reconnect, wenn die Verbindung zustandslos ist und der Kontext kostengünstig neu aufgebaut werden kann.
- Der JWT-
exp-Claim ist ein NumericDate in Sekunden seit der Unix-Epoche, daher muss die clientseitige Refresh-Planung überexp * 1000konvertiert werden, bevor ein Vergleich mitDate.now()erfolgt. - Ein häufiges stilles Fehlerbild ist ein Socket, der bei Token-Ablauf geschlossen wird, während die Benutzeroberfläche weiterhin einen „verbunden”-Status anzeigt und alle nachfolgenden Nachrichten verwirft — sichtbar im Session-Replay, unsichtbar in Server-Logs.
Warum sich WebSocket-Authentifizierung unterscheidet
WebSocket-Authentifizierung ist auf Browser-Ebene eingeschränkt: Die JavaScript-WebSocket-API bietet keine Möglichkeit, einen benutzerdefinierten Header an den Opening-Handshake anzuhängen. Jede WebSocket-Verbindung beginnt als HTTP-GET mit einem Upgrade: websocket-Header, aber der Browser kontrolliert diese Anfrage vollständig — der eigene Code liefert lediglich die URL und eine optionale Subprotokoll-Liste. Das WebSocket-Protokoll selbst stellt klar, dass es dieses Problem nicht löst: Gemäß RFC 6455 §10.5 „schreibt das Protokoll keine bestimmte Methode vor, mit der Server Clients während des WebSocket-Handshakes authentifizieren können.”
Die fehlende Header-Unterstützung des Browsers lässt vier praktische Mechanismen übrig, die alle als Workaround fungieren:
- Query-Parameter-Token — das Token in die Verbindungs-URL einbetten.
- Cookie/Session — den Browser ein vorhandenes Session-Cookie automatisch mit der Upgrade-Anfrage mitsenden lassen.
Sec-WebSocket-Protocol-Subprotokoll — das Token im Subprotokoll-Array unterbringen.- First-Message-Authentifizierung — den Socket ohne Authentifizierung öffnen und die Credentials anschließend als erste Nachricht senden.
Der Rest dieses Abschnitts erläutert jeden Ansatz mit Browser-Client-Code und Node.js-Server-Code unter Verwendung der ws-Bibliothek (aktuell stabile Version: 8.x).
Discover how at OpenReplay.com.
Query-Parameter-Token
Das Token wird in die Verbindungs-URL eingebettet und während des HTTP-Upgrades validiert, bevor Verbindungsressourcen zugewiesen werden. Dies ist die einfachste und am weitesten verbreitete Methode. Ihr Vorteil liegt in der schnellen Ablehnung — der Server kann ein 401 zurückgeben, bevor der Socket überhaupt aufgebaut wird.
// Browser-Client
const token = localStorage.getItem('authToken');
const socket = new WebSocket(`wss://api.example.com/ws?token=${encodeURIComponent(token)}`);
// Node.js-Server — ws@8.21.0
import { WebSocketServer } from 'ws';
import { verify } from 'jsonwebtoken';
const wss = new WebSocketServer({ noServer: true });
server.on('upgrade', (req, socket, head) => {
const { searchParams } = new URL(req.url, 'wss://api.example.com');
const token = searchParams.get('token');
try {
const user = verify(token, process.env.JWT_SECRET);
wss.handleUpgrade(req, socket, head, (ws) => {
ws.user = user;
wss.emit('connection', ws, req);
});
} catch {
socket.write('HTTP/1.1 401 Unauthorized\r\n\r\n');
socket.destroy();
}
});
Konkretes Risiko: Ein Token in der WebSocket-URL wird standardmäßig in den nginx- und Apache-Access-Logs erfasst — beide Standard-Logformate (combined / %r) enthalten die vollständige Request-Zeile einschließlich Query-String — kann im Browser-Verlauf erscheinen und über den Referer-Header durchsickern, wenn die Seite nach dem Verbindungsaufbau navigiert. Kurzlebige Tokens (5–15 Minuten sind eine Branchenkonvention, kein OWASP-dokumentierter Richtwert) reduzieren, aber eliminieren diese Exposition nicht vollständig.
Cookie / Session
Cookie-basierte Authentifizierung nutzt eine bereits über HTTP etablierte Session: Der Browser hängt automatisch Same-Domain-Cookies an die Upgrade-Anfrage an, sodass clientseitig keinerlei Authentifizierungscode erforderlich ist. Dies ist die reibungsloseste Methode, wenn der WebSocket-Endpunkt dieselbe Domain wie die Anwendung teilt, über die der Benutzer eingeloggt wurde.
// Browser-Client — kein Token-Handling erforderlich; das Cookie wird automatisch mitgesendet
const socket = new WebSocket('wss://app.example.com/ws');
// Node.js-Server — ws@8.21.0
import { parse } from 'cookie';
server.on('upgrade', (req, socket, head) => {
const origin = req.headers.origin;
if (origin !== 'https://app.example.com') {
socket.write('HTTP/1.1 403 Forbidden\r\n\r\n');
return socket.destroy();
}
const cookies = parse(req.headers.cookie || '');
const session = sessionStore.get(cookies.sid);
if (!session) {
socket.write('HTTP/1.1 401 Unauthorized\r\n\r\n');
return socket.destroy();
}
wss.handleUpgrade(req, socket, head, (ws) => {
ws.user = session.user;
wss.emit('connection', ws, req);
});
});
Konkretes Risiko: Cookie-basierte WebSocket-Authentifizierung erfordert sowohl die Validierung des Origin-Headers auf dem Server als auch das Cookie-Attribut SameSite=Strict oder SameSite=Lax. Wie die MDN-Dokumentation zu SameSite beschreibt, steuert SameSite, ob ein Cookie bei Cross-Site-Anfragen gesendet wird; SameSite=None (erforderlich für echte Cross-Site-Cookies) öffnet die CSRF-Angriffsfläche wieder, die SameSite ursprünglich schließen sollte. Cookies versagen zudem bei unterschiedlichen Domains, was der Hauptgrund ist, warum Teams auf die folgenden zwei Methoden zurückgreifen.
Sec-WebSocket-Protocol-Subprotokoll
Ein Token kann als Subprotokoll-Wert übergeben werden, da das Subprotokoll-Array der einzige Teil des Handshakes ist, den der Browser tatsächlich exponiert. Der Sec-WebSocket-Protocol-Header wurde für die Aushandlung von Subprotokollen auf Anwendungsebene konzipiert, nicht für die Übertragung von Authentifizierungs-Tokens; seine Verwendung für Auth ist ein Workaround, der in allen gängigen Browsern funktioniert, aber als letzter Ausweg behandelt werden sollte.
Subprotokoll-Werte müssen gültige token-Werte ohne Trennzeichen sein, daher muss das Token als ungepolstertes Base64url kodiert werden — die Zeichen / und = des Standard-Base64 sind hier nicht zulässig. Das Base64url-Alphabet ist in RFC 4648 §5 definiert.
// Browser-Client — Token als ungepolsterter Base64url-Subprotokoll-Wert
const token = localStorage.getItem('authToken'); // bereits Base64url, ungepolstert
const socket = new WebSocket('wss://api.example.com/ws', ['auth.bearer', token]);
// Node.js-Server — ws@8.21.0
const wss = new WebSocketServer({
noServer: true,
handleProtocols: (protocols) => {
// protocols ist ein Set; der zweite Eintrag ist unser Token
const [, token] = [...protocols];
return validate(token) ? 'auth.bearer' : false;
},
});
Konkretes Risiko: Wie bei der Query-Parameter-Methode kann der Subprotokoll-Wert in Logs landen, die Handshake-Header aufzeichnen, und die Kodierungsanforderung (ungepolstertes Base64url) ist fehleranfällig. Diese Methode sollte auf Fälle beschränkt werden, in denen Cookies cross-domain blockiert sind und eine Query-Parameter-Exposition inakzeptabel ist.
First-Message-Authentifizierung
Die Verbindung wird ohne Authentifizierung geöffnet und der Client sendet die Credentials als erste Nachricht; der Server validiert diese, bevor er irgendetwas anderes verarbeitet. Dadurch bleiben Tokens vollständig aus URLs und Logs heraus, auf Kosten eines Queuing-und-Timeout-Protokolls, das selbst implementiert werden muss.
// Browser-Client — Anwendungsnachrichten in die Warteschlange stellen, bis AUTH erfolgreich ist
const socket = new WebSocket('wss://api.example.com/ws');
const queue = [];
let authed = false;
socket.onopen = () => {
socket.send(JSON.stringify({ type: 'AUTH', token: localStorage.getItem('authToken') }));
};
socket.onmessage = (e) => {
const msg = JSON.parse(e.data);
if (msg.type === 'AUTH_OK') {
authed = true;
queue.forEach((m) => socket.send(m));
queue.length = 0;
}
};
function send(data) {
const m = JSON.stringify(data);
authed ? socket.send(m) : queue.push(m);
}
// Node.js-Server — ws@8.21.0
wss.on('connection', (ws) => {
const timer = setTimeout(() => ws.close(4001, 'auth timeout'), 7000);
ws.once('message', (raw) => {
const msg = JSON.parse(raw);
if (msg.type !== 'AUTH') return ws.close(4002, 'expected AUTH');
try {
ws.user = verify(msg.token, process.env.JWT_SECRET);
clearTimeout(timer);
ws.send(JSON.stringify({ type: 'AUTH_OK' }));
} catch {
ws.close(4003, 'invalid token');
}
});
});
Konkretes Risiko: Ein Server, der nicht authentifizierte WebSocket-Verbindungen akzeptiert, muss ein hartes Auth-Timeout durchsetzen — üblicherweise 5–10 Sekunden, eine Konvention ohne Spec-Grundlage — und jede Verbindung schließen, die innerhalb dieses Zeitfensters keine gültigen Credentials sendet. Ohne diese Maßnahme kann ein Angreifer Verbindungslimits mit offenen, aber nicht authentifizierten Sockets erschöpfen. Der richtige Wert hängt von der eigenen p95-Round-Trip-Zeit ab: 5 Sekunden eignen sich für Verbindungen mit geringer Latenz, 10 Sekunden sind für mobile und hochlatente Clients sicherer.
Methodenvergleich und Entscheidungsregel
Die Wahl der Methode sollte von den Einschränkungen des eigenen Deployments abhängen, nicht davon, welche Methode abstrakt betrachtet „am sichersten” ist — alle vier sind bei korrekter Implementierung sicher. Die nachstehende Tabelle fasst die Kompromisse zusammen; die anschließende Entscheidungsregel löst die häufigsten Fälle.
| Methode | Token-Exposition | CSRF-Risiko | Cross-Domain | Komplexität | Einsatz wenn |
|---|---|---|---|---|---|
| Query-Parameter-Token | Logs, Verlauf, Referer | Keines | Ja | Gering | Server-Logs kontrollierbar, einfachste Implementierung gewünscht |
| Cookie / Session | Keine (Cookie ist HttpOnly) | Ja (Abschwächung mit SameSite + Origin) | Nein | Gering | Gleiche Domain, bestehende Session |
| Subprotokoll-Header | Handshake-Logs | Keines | Ja | Mittel | Cookies cross-domain blockiert, Query-Parameter inakzeptabel |
| First-Message | Keine | Keine | Ja | Hoch | Tokens dürfen URLs nicht erscheinen |
Die Entscheidungsregel: Query-Parameter-Tokens verwenden, wenn die Server-Logs kontrollierbar sind und eine möglichst einfache Implementierung gewünscht wird; Cookies verwenden, wenn man sich auf derselben Domain befindet und bereits eine Session existiert; First-Message-Authentifizierung verwenden, wenn Tokens vollständig aus URLs herausgehalten werden müssen und die Queuing-Komplexität akzeptabel ist; den Subprotokoll-Header nur dann verwenden, wenn Cookies cross-domain blockiert sind und eine Query-Parameter-Exposition inakzeptabel ist — dieser Ansatz ist nicht standardkonform und sollte der letzte Ausweg sein. Teams, die keinen dieser Ansätze selbst verwalten möchten, greifen häufig auf eine verwaltete Realtime-Plattform zurück, die den Token-Lebenszyklus als Teil des Dienstes übernimmt.
Token-Erneuerung bei langlebigen Verbindungen
Eine WebSocket-Verbindung überlebt ihren Token, daher muss eine Erneuerungsstrategie von Anfang an festgelegt werden. Es gibt zwei Ansätze: das Token In-Band über den geöffneten Socket aktualisieren oder die Verbindung schließen und mit einem neuen Token neu aufbauen. In-Band-Token-Aktualisierung — das Senden eines neuen Tokens über die bestehende Verbindung — sollte verwendet werden, wenn der Socket zustandsbehaftete Subscriptions oder ausstehende Operationen trägt, die bei einem Reconnect verloren gehen würden; Close-and-Reconnect sollte verwendet werden, wenn die Verbindung zustandslos ist und der Client den Kontext kostengünstig ohne Datenverlust neu aufbauen kann.
Der Client plant die Aktualisierung anhand des eigenen Ablaufzeitpunkts des JWTs. Der exp-Claim ist gemäß RFC 7519 §4.1.4 ein NumericDate in Sekunden seit der Unix-Epoche, daher muss er mit 1000 multipliziert werden, bevor ein Vergleich mit Date.now() erfolgt.
// Browser — In-Band-Aktualisierung 60s vor Ablauf planen, bei Fehler Reconnect als Fallback
class WebSocketAuthManager {
constructor(url) {
this.url = url;
this.connect();
}
connect() {
this.ws = new WebSocket(`${this.url}?token=${getToken()}`);
this.ws.onopen = () => this.scheduleRefresh();
this.ws.onmessage = (e) => {
const msg = JSON.parse(e.data);
if (msg.type === 'TOKEN_REFRESH_OK') this.scheduleRefresh();
};
}
scheduleRefresh() {
const { exp } = parseJwt(getToken()); // exp ist in Sekunden
const fireAt = exp * 1000 - Date.now() - 60_000; // 60s vor Ablauf
clearTimeout(this.timer);
this.timer = setTimeout(() => this.refresh(), Math.max(0, fireAt));
}
async refresh() {
try {
const fresh = await fetchNewToken();
setToken(fresh);
this.ws.send(JSON.stringify({ type: 'TOKEN_REFRESH', token: fresh }));
} catch {
this.ws.close(4004, 'refresh failed'); // Fallback auf sauberen Reconnect
this.connect();
}
}
}
Der Server validiert das aktualisierte Token und aktualisiert die dem Socket zugeordnete Session — er baut die Verbindung nicht ab, was der eigentliche Zweck des In-Band-Pfads ist:
// Node.js-Server — ws@8.21.0
ws.on('message', (raw) => {
const msg = JSON.parse(raw);
if (msg.type === 'TOKEN_REFRESH') {
try {
ws.user = verify(msg.token, process.env.JWT_SECRET);
ws.send(JSON.stringify({ type: 'TOKEN_REFRESH_OK' }));
} catch {
ws.close(4003, 'invalid refresh token');
}
}
});
Autorisierung als fortlaufender Kontrollmechanismus
WebSocket-Authentifizierung ist kein einmaliges Ereignis beim Verbindungsaufbau: Da Verbindungen langlebig sind, kann ein Token, der zum Zeitpunkt des Handshakes gültig war, ablaufen, widerrufen werden oder seine zugehörigen Berechtigungen verlieren, während der Socket noch geöffnet ist — das macht nachrichtenbasierte Autorisierung zu einer produktiven Anforderung und nicht zu einer optionalen Härtungsmaßnahme. Berechtigungen ändern sich während einer aktiven Verbindung durch Admin-Aktionen, Subscription-Ablauf oder Moderation — und der Handshake, der vor einer Stunde stattfand, kann all das nicht berücksichtigen.
Die Lösung besteht darin, die Autorisierung bei jeder eingehenden Nachricht zu prüfen, nicht nur beim Verbindungsaufbau. Der Handshake stellt die Identität fest, jede Nachricht ist eine eigenständige Autorisierungsentscheidung:
// Node.js-Server — nachrichtenbasierte Berechtigungsprüfung
const PERMISSIONS = { admin: ['read', 'write', 'delete'], user: ['read', 'write'], guest: ['read'] };
ws.on('message', (raw) => {
const msg = JSON.parse(raw);
const allowed = PERMISSIONS[ws.user.role] || [];
if (!allowed.includes(msg.action)) {
return ws.send(JSON.stringify({ type: 'FORBIDDEN', action: msg.action }));
}
handle(msg, ws);
});
Ergänzen Sie dies durch eine Widerrufsprüfung, damit ein ausgeloggter oder gesperrter Benutzer nicht weiterhin über einen bereits geöffneten Socket operieren kann. Ein kleines In-Memory-Set mit widerrufenen Token-IDs funktioniert für einen einzelnen Prozess; ein gemeinsamer Speicher wie Redis ist erforderlich, sobald mehrere WebSocket-Knoten betrieben werden, da ein Widerruf für denjenigen Knoten sichtbar sein muss, der die Verbindung hält.
Sicherheits-Checkliste und Debugging stiller Fehler
Die Absicherung einer WebSocket-Verbindung lässt sich auf eine kurze, konkrete Checkliste reduzieren. Diese sollte vor dem Deployment durchgegangen werden:
- Ausschließlich
wss://verwenden. RFC 6455 §10.6 empfiehlt den Betrieb von WebSockets über TLS für Vertraulichkeit und Integrität. Einfachesws://legt Tokens und Nachrichten während der Übertragung offen. - Tokens kurzlebig halten. Das Session Management Cheat Sheet von OWASP empfiehlt Idle-Timeouts von 2–5 Minuten für hochwertige Anwendungen und 15–30 Minuten für geringere Risikostufen; für im Browser gespeicherte Tokens eher den kürzeren Bereich wählen.
- Auth-Timeout erzwingen bei First-Message-Authentifizierung (5–10 Sekunden, per Konvention) und nicht authentifizierte Sockets schließen.
- Verbindungen rate-limitieren pro IP oder pro Benutzer, um nicht authentifizierten Socket-Churn zu begrenzen. Jede konkrete Zahl (etwa eine maximale gleichzeitige Anzahl) ist illustrativ, kein Standard — den Wert aus dem eigenen Traffic-Baseline ableiten.
- Widerruf unterstützen. Eine Widerrufsliste beim Verbindungsaufbau und bei jeder Nachricht prüfen, damit eine ausgeloggte Session nicht auf einem offenen Socket fortbestehen kann.
Originvalidieren bei Cookie-basierter Authentifizierung undSameSite=StrictoderLaxsetzen.
Diese Punkte sind wichtig, weil WebSocket-Authentifizierung still versagt. Wenn ein kurzlebiges Token während einer Session abläuft und der Server den Socket schließt, löst der Browser ein close-Event aus; behandelt die Anwendung dieses Event nicht, zeigt die Benutzeroberfläche weiterhin einen „verbunden”-Status, während alle nachfolgenden Nachrichten still verworfen werden — ein Fehlerbild, das in Server-Logs unsichtbar ist, im Session-Replay jedoch sichtbar wird, wo nach der letzten erfolgreichen Nachricht clientseitige Stille folgt. Dasselbe gilt für das First-Message-Muster: Bei einer langsamen Verbindung können Nachrichten, die vor Abschluss der Authentifizierung in die Warteschlange gestellt wurden, verworfen werden, wenn das Auth-Timeout zuerst ausgelöst wird — und das Session-Replay dieser Sitzungen zeigt, wie der Client Nachrichten sendet, die keine Antwort erzeugen, während der Socket noch geöffnet erscheint. Das Replay der Client-Seite ist häufig der einzige Weg, eine Fehlerklasse zu erklären, die Server-Logs nur als Close-Frame ohne Kontext aufzeichnen.
Fazit
Den fehlenden Authorization-Header als Ausgangspunkt betrachten, nicht als das gesamte Problem: Eine Übertragungsmethode anhand der obigen Entscheidungsregel auswählen, dann die Erneuerungsstrategie festlegen und nachrichtenbasierte Autorisierung implementieren, bevor die Verbindung in der Produktion langlebig wird. Der Handshake beweist, wer sich verbunden hat; alles danach ist der Bereich, in dem echte WebSocket-Sicherheit stattfindet. Als ersten Schritt einen bestehenden Socket auditieren — sicherstellen, dass er über wss:// läuft, abgelaufene Tokens während der Session ablehnt und eine geschlossene Verbindung dem Benutzer anzeigt, anstatt Nachrichten still zu verwerfen.
FAQs
Kann ich einen Authorization-Bearer-Header mit einer Browser-WebSocket-Verbindung senden?
Nein. Der WebSocket-Konstruktor des Browsers akzeptiert ausschließlich eine URL und ein optionales Subprotokoll-Array, sodass keine API existiert, um einen benutzerdefinierten Authorization-Header an den Opening-Handshake anzuhängen. Die vier praktischen Alternativen sind ein Token im Query-String, ein Session-Cookie, das der Browser automatisch sendet, ein im Sec-WebSocket-Protocol-Subprotokoll-Wert kodiertes Credential oder ein Credential, das als erste Nachricht nach dem Verbindungsaufbau gesendet wird. Native WebSocket-Bibliotheken außerhalb des Browsers, wie Node.js-Clients, können beliebige Header setzen, Browser-Code jedoch nicht.
Was passiert mit Nachrichten, die vor Abschluss der First-Message-Authentifizierung gesendet werden?
Nachrichten, die vor Abschluss des AUTH-Handshakes gesendet werden, müssen clientseitig in eine Warteschlange gestellt und erst nach Bestätigung der Authentifizierung durch den Server geleert werden, da früher gesendete Nachrichten still verworfen werden können. Wenn das Auth-Timeout des Servers ausgelöst wird, bevor gültige Credentials empfangen wurden — typischerweise innerhalb eines Fensters von 5 bis 10 Sekunden — wird die Verbindung geschlossen und alle ausstehenden oder in der Warteschlange befindlichen Nachrichten gehen verloren. Bei langsamen Verbindungen führt dies zu einem Fehlerbild, bei dem der Socket noch geöffnet erscheint, Nachrichten aber keine Antwort erhalten. Anwendungsseitige Sendevorgänge immer hinter einem Authentifizierungs-Flag absichern.
Sollte ich ein WebSocket-Token In-Band aktualisieren oder die Verbindung schließen und neu aufbauen?
In-Band-Aktualisierung — das Senden eines neuen Tokens über den bestehenden Socket — sollte verwendet werden, wenn die Verbindung zustandsbehaftete Subscriptions oder ausstehende Operationen trägt, die bei einem Reconnect verloren gehen würden. Close-and-Reconnect sollte verwendet werden, wenn die Verbindung zustandslos ist und der Client den Kontext kostengünstig ohne Datenverlust neu aufbauen kann. Die Wahl ist architektonischer, nicht stilistischer Natur: Ein Reconnect baut den serverseitigen Subscription-Zustand ab, sodass bei einem Live-Feed mit vielen aktiven Channels die In-Band-Aktualisierung den Re-Subscription-Overhead und verlorene Events während der Unterbrechung vermeidet.
Warum zeigt meine WebSocket-Benutzeroberfläche nach Token-Ablauf noch 'verbunden' an?
Der Server schließt den Socket bei Token-Ablauf und der Browser löst ein Close-Event aus; wenn das State-Management der Anwendung dieses Event jedoch nicht behandelt, zeigt die Benutzeroberfläche weiterhin einen verbundenen Status, während alle nachfolgenden Nachrichten still verworfen werden. Dieser Fehler ist in Server-Logs unsichtbar — diese zeichnen nur einen Close-Frame ohne Kontext auf — aber im Session-Replay sichtbar als letzte erfolgreiche Nachricht gefolgt von clientseitiger Stille. Das Close-Event explizit behandeln, um die Trennung anzuzeigen und einen Reconnect auszulösen.