WebSocket auf TypeScript: Fortgeschrittene Techniken für Echtzeitanwendungen
WebSocket bietet eine permanente bidirektionale Verbindung zwischen Client und Server, was es ideal für Echtzeitanwendungen macht: Chats, Benachrichtigungen, gemeinsames Bearbeiten und Online-Spiele. In diesem Artikel betrachten wir fortgeschrittene Techniken für die Arbeit mit WebSocket auf TypeScript, die über einen einfachen Echo-Server hinausgehen.
1. Architektur mit Raumverwaltung (Rooms)
In realen Anwendungen wird selten eine globale Broadcast-Nachricht an alle Clients verwendet. Viel häufiger ist eine logische Trennung der Clients in Räumen erforderlich (z. B. Chat-Räume oder Spielsitzungen). Betrachten wir eine Implementierung auf TypeScript unter Verwendung der Bibliothek ws.
import { WebSocketServer, WebSocket } from 'ws';
interface Room { id: string; clients: Set<WebSocket>;}
class RoomManager { private rooms: Map<string, Room> = new Map();
createRoom(roomId: string): void { if (!this.rooms.has(roomId)) { this.rooms.set(roomId, { id: roomId, clients: new Set() }); } }
joinRoom(roomId: string, client: WebSocket): void { this.createRoom(roomId); this.rooms.get(roomId)!.clients.add(client); client.send(JSON.stringify({ type: 'room_joined', roomId })); }
leaveRoom(roomId: string, client: WebSocket): void { const room = this.rooms.get(roomId); if (room) { room.clients.delete(client); if (room.clients.size === 0) { this.rooms.delete(roomId); } } }
broadcastToRoom(roomId: string, message: object, sender?: WebSocket): void { const room = this.rooms.get(roomId); if (room) { const data = JSON.stringify(message); room.clients.forEach(client => { if (client.readyState === WebSocket.OPEN && client !== sender) { client.send(data); } }); } }}
const wss = new WebSocketServer({ port: 8080 });const roomManager = new RoomManager();
wss.on('connection', (ws: WebSocket) => { ws.on('message', (raw: Buffer) => { try { const msg = JSON.parse(raw.toString()); switch (msg.type) { case 'join': roomManager.joinRoom(msg.roomId, ws); break; case 'leave': roomManager.leaveRoom(msg.roomId, ws); break; case 'message': roomManager.broadcastToRoom(msg.roomId, { type: 'chat', user: msg.user, text: msg.text }, ws); break; } } catch (e) { ws.send(JSON.stringify({ type: 'error', message: 'Invalid JSON' })); } });
ws.on('close', () => { // Bereinigung: Client aus allen Räumen entfernen roomManager.leaveRoom('*', ws); });});Dieser Code demonstriert die sichere Arbeit mit Räumen: Erstellung bei Bedarf, automatische Bereinigung leerer Räume und Ausschluss des Absenders vom Broadcast.
2. Authentifizierung und Zustandsverwaltung
WebSocket-Verbindungen müssen authentifiziert werden. Ein fortgeschrittener Ansatz ist die Überprüfung des Tokens beim Verbindungsaufbau und die Aufrechterhaltung der Sitzung.
import { IncomingMessage } from 'http';import { WebSocketServer, WebSocket } from 'ws';
interface AuthenticatedSocket extends WebSocket { userId?: string; username?: string;}
const wss = new WebSocketServer({ port: 8080, verifyClient: (info: { req: IncomingMessage }, callback: (res: boolean) => void) => { const token = extractToken(info.req.url || ''); if (token && validateToken(token)) { callback(true); } else { callback(false); } }});
function extractToken(url: string): string | null { const params = new URLSearchParams(url.split('?')[1] || ''); return params.get('token');}
function validateToken(token: string): boolean { // Hier sollte eine echte Überprüfung von JWT oder einem anderen Token erfolgen return token.length > 10;}
wss.on('co