NestJS und WebSockets 2026: Echtzeit-Kommunikation, Gateways und Interview-Fragen

WebSockets in NestJS meistern mit Gateway-Mustern, Socket.IO-Integration, Authentifizierung, Fehlerbehandlung und häufigen Interview-Fragen für 2026.

NestJS WebSocket Echtzeit-Kommunikation Gateway

NestJS WebSockets bieten einen strukturierten Ansatz für Echtzeit-Kommunikation mittels des Gateway-Musters. Im Gegensatz zu rohen WebSocket-Implementierungen abstrahiert NestJS die Komplexität durch Decorators und integriert sich nahtlos in das Dependency-Injection-System.

Kurze Definition

Ein WebSocket Gateway in NestJS ist eine Klasse, die mit @WebSocketGateway() dekoriert wird und bidirektionale Kommunikation zwischen Client und Server ermöglicht. Es unterstützt mehrere Adapter (Socket.IO, ws) und integriert sich mit NestJS Guards, Pipes und Interceptors.

Einrichten eines WebSocket Gateways mit Socket.IO

Der Standard-Adapter in NestJS verwendet Socket.IO, das automatische Wiederverbindung, Room-Unterstützung und Fallback zu HTTP Long-Polling bietet. Die Installation erfordert das plattformspezifische Paket zusammen mit dem Core-WebSockets-Modul.

bash
# terminal
npm install @nestjs/websockets @nestjs/platform-socket.io socket.io

Ein einfaches Gateway lauscht auf eingehende Nachrichten und kann Antworten an verbundene Clients broadcasten.

chat.gateway.tstypescript
import {
  WebSocketGateway,
  WebSocketServer,
  SubscribeMessage,
  MessageBody,
  ConnectedSocket,
} from '@nestjs/websockets';
import { Server, Socket } from 'socket.io';

@WebSocketGateway({
  cors: { origin: '*' }, // Configure CORS for browser clients
})
export class ChatGateway {
  @WebSocketServer()
  server: Server; // Access to the underlying Socket.IO server

  @SubscribeMessage('message') // Listen for 'message' events
  handleMessage(
    @MessageBody() data: { text: string; room: string },
    @ConnectedSocket() client: Socket,
  ): void {
    // Broadcast to all clients in the room except sender
    client.to(data.room).emit('message', {
      text: data.text,
      senderId: client.id,
      timestamp: Date.now(),
    });
  }
}

Der @SubscribeMessage-Decorator bindet eine Methode an einen spezifischen Event-Namen. @MessageBody() extrahiert den Payload, während @ConnectedSocket() Zugriff auf den Client-Socket für gezielte Antworten bietet.

Lifecycle Hooks für Verbindungsmanagement

NestJS Gateways implementieren Lifecycle-Interfaces für die Behandlung von Client-Verbindungen und -Trennungen. Diese Hooks ermöglichen Ressourcenbereinigung, Präsenzverfolgung und Verbindungsvalidierung.

presence.gateway.tstypescript
import {
  WebSocketGateway,
  OnGatewayConnection,
  OnGatewayDisconnect,
  OnGatewayInit,
} from '@nestjs/websockets';
import { Server, Socket } from 'socket.io';
import { Logger } from '@nestjs/common';

@WebSocketGateway()
export class PresenceGateway
  implements OnGatewayInit, OnGatewayConnection, OnGatewayDisconnect
{
  private readonly logger = new Logger(PresenceGateway.name);
  private connectedUsers = new Map<string, { joinedAt: Date }>();

  afterInit(server: Server): void {
    // Called once when the gateway initializes
    this.logger.log('WebSocket Gateway initialized');
  }

  handleConnection(client: Socket): void {
    // Track new connections
    this.connectedUsers.set(client.id, { joinedAt: new Date() });
    this.logger.log(`Client connected: ${client.id}`);
  }

  handleDisconnect(client: Socket): void {
    // Cleanup on disconnect
    this.connectedUsers.delete(client.id);
    this.logger.log(`Client disconnected: ${client.id}`);
  }
}

Die drei Lifecycle-Interfaces dienen unterschiedlichen Zwecken: OnGatewayInit läuft einmal beim Start, OnGatewayConnection wird pro Client-Verbindung ausgelöst, und OnGatewayDisconnect behandelt die Bereinigung beim Verlassen von Clients.

Authentifizierung mit WebSocket Guards

WebSocket-Verbindungen erfordern Authentifizierungsvalidierung bevor Zugriff auf geschützte Events gewährt wird. NestJS Guards funktionieren mit Gateways, obwohl sich der Ausführungskontext von HTTP-Anfragen unterscheidet. Die offizielle NestJS WebSockets-Dokumentation behandelt die Guard-Integration im Detail.

ws-auth.guard.tstypescript
import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
import { WsException } from '@nestjs/websockets';
import { JwtService } from '@nestjs/jwt';
import { Socket } from 'socket.io';

@Injectable()
export class WsAuthGuard implements CanActivate {
  constructor(private jwtService: JwtService) {}

  canActivate(context: ExecutionContext): boolean {
    const client: Socket = context.switchToWs().getClient();
    // Extract token from handshake auth or query params
    const token =
      client.handshake.auth?.token ||
      client.handshake.query?.token;

    if (!token) {
      throw new WsException('Missing authentication token');
    }

    try {
      const payload = this.jwtService.verify(token as string);
      // Attach user data to socket for later use
      client.data.user = payload;
      return true;
    } catch {
      throw new WsException('Invalid token');
    }
  }
}

Der Guard wird auf die Gateway-Klasse oder einzelne Message-Handler mit dem @UseGuards()-Decorator angewendet. Die WsException-Klasse wirft Fehler, die der Client über das Socket.IO Error-Event empfängt.

secure-chat.gateway.tstypescript
import { UseGuards } from '@nestjs/common';
import { WebSocketGateway, SubscribeMessage } from '@nestjs/websockets';
import { WsAuthGuard } from './ws-auth.guard';

@WebSocketGateway()
@UseGuards(WsAuthGuard) // Protect all handlers in this gateway
export class SecureChatGateway {
  @SubscribeMessage('privateMessage')
  handlePrivateMessage(): void {
    // Only authenticated clients reach this handler
  }
}

Für Fragen zur Modul-Level-Authentifizierung bietet das NestJS Authentifizierungs-Interview-Modul Informationen zu JWT-Strategien und Session-Management.

Bereit für deine Node.js / NestJS-Interviews?

Übe mit unseren interaktiven Simulatoren, Flashcards und technischen Tests.

Room-basierte Broadcasting-Muster

Socket.IO Rooms ermöglichen gezielte Nachrichtenzustellung an Teilmengen verbundener Clients. Häufige Anwendungsfälle umfassen Chat-Räume, Spiel-Lobbys und Live-Kollaborationsfunktionen.

room.gateway.tstypescript
import {
  WebSocketGateway,
  SubscribeMessage,
  ConnectedSocket,
  MessageBody,
  WebSocketServer,
} from '@nestjs/websockets';
import { Server, Socket } from 'socket.io';

@WebSocketGateway()
export class RoomGateway {
  @WebSocketServer()
  server: Server;

  @SubscribeMessage('joinRoom')
  handleJoinRoom(
    @MessageBody() roomId: string,
    @ConnectedSocket() client: Socket,
  ): { event: string; data: string } {
    // Add client to the specified room
    client.join(roomId);
    // Notify others in the room
    client.to(roomId).emit('userJoined', { userId: client.id });
    return { event: 'joinedRoom', data: roomId };
  }

  @SubscribeMessage('leaveRoom')
  handleLeaveRoom(
    @MessageBody() roomId: string,
    @ConnectedSocket() client: Socket,
  ): void {
    client.leave(roomId);
    client.to(roomId).emit('userLeft', { userId: client.id });
  }

  @SubscribeMessage('roomBroadcast')
  handleRoomBroadcast(
    @MessageBody() payload: { roomId: string; message: string },
  ): void {
    // Send to all clients in room, including sender
    this.server.to(payload.roomId).emit('roomMessage', payload.message);
  }
}

Der Unterschied zwischen client.to(room).emit() und server.to(room).emit() ist wichtig: Ersteres schließt den Sender aus, während Letzteres alle Room-Mitglieder einschließt.

Fehlerbehandlung mit Exception Filters

WebSocket-Exceptions erfordern dedizierte Filter, da HTTP Exception Filters nicht auf Gateway-Kontexte anwendbar sind. Benutzerdefinierte Filter fangen WsException ab und formatieren Fehlerantworten für Clients.

ws-exception.filter.tstypescript
import { Catch, ArgumentsHost, ExceptionFilter } from '@nestjs/common';
import { WsException } from '@nestjs/websockets';
import { Socket } from 'socket.io';

@Catch(WsException)
export class WsExceptionFilter implements ExceptionFilter {
  catch(exception: WsException, host: ArgumentsHost): void {
    const client: Socket = host.switchToWs().getClient();
    const error = exception.getError();
    // Send structured error to client
    client.emit('error', {
      type: 'WsException',
      message: typeof error === 'string' ? error : error,
      timestamp: new Date().toISOString(),
    });
  }
}

Filter werden auf Gateway-Ebene angewendet für konsistente Fehlerbehandlung über alle Message-Handler hinweg.

filtered.gateway.tstypescript
import { UseFilters } from '@nestjs/common';
import { WebSocketGateway } from '@nestjs/websockets';
import { WsExceptionFilter } from './ws-exception.filter';

@WebSocketGateway()
@UseFilters(WsExceptionFilter)
export class FilteredGateway {
  // All handlers benefit from centralized error handling
}

Dieses Muster spiegelt die NestJS-Philosophie von Decorators und Filtern wider, die im Middleware und Interceptors Modul beschrieben wird.

Skalierung von WebSockets mit Redis Adapter

Einzelserver-WebSocket-Deployments versagen, wenn Load Balancing Clients über mehrere Instanzen verteilt. Der Socket.IO Redis-Adapter synchronisiert Events über Instanzen hinweg durch einen Pub/Sub-Mechanismus.

app.module.tstypescript
import { Module } from '@nestjs/common';
import { createAdapter } from '@socket.io/redis-adapter';
import { createClient } from 'redis';
import { ChatGateway } from './chat.gateway';

@Module({
  providers: [
    ChatGateway,
    {
      provide: 'REDIS_ADAPTER',
      useFactory: async () => {
        const pubClient = createClient({ url: process.env.REDIS_URL });
        const subClient = pubClient.duplicate();
        await Promise.all([pubClient.connect(), subClient.connect()]);
        return createAdapter(pubClient, subClient);
      },
    },
  ],
})
export class AppModule {}

Das Gateway verwendet dann den Adapter für instanzübergreifende Kommunikation.

scalable.gateway.tstypescript
import {
  WebSocketGateway,
  WebSocketServer,
  OnGatewayInit,
} from '@nestjs/websockets';
import { Inject } from '@nestjs/common';
import { Server } from 'socket.io';
import { Adapter } from 'socket.io-adapter';

@WebSocketGateway()
export class ScalableGateway implements OnGatewayInit {
  @WebSocketServer()
  server: Server;

  constructor(@Inject('REDIS_ADAPTER') private redisAdapter: Adapter) {}

  afterInit(): void {
    // Attach Redis adapter for multi-instance support
    this.server.adapter(this.redisAdapter as any);
  }
}

Mit dem Redis-Adapter erreicht eine Nachricht, die auf einer Server-Instanz emittiert wird, Clients, die mit jeder Instanz im Cluster verbunden sind.

Häufige Interview-Fragen zu NestJS WebSockets

Technische Interviews prüfen oft das Verständnis von Echtzeit-Architekturentscheidungen und NestJS-spezifischen Implementierungsdetails.

Häufig gefragt

Wie behandelt NestJS WebSocket-Authentifizierung anders als HTTP?

HTTP-Middleware wird für WebSocket-Verbindungen nicht ausgeführt. Authentifizierung erfolgt während der Handshake-Phase oder durch Guards, die auf das Gateway angewendet werden. Token-Validierung geschieht typischerweise in handleConnection() oder einem benutzerdefinierten Guard, der aus socket.handshake.auth liest.

Was ist der Unterschied zwischen @WebSocketGateway() Port-Konfiguration und dem Hauptanwendungsport?

Standardmäßig teilen sich WebSocket Gateways den HTTP-Server-Port. Die Angabe eines Ports in @WebSocketGateway(3001) erstellt einen separaten WebSocket-Server auf diesem Port. Geteilte Ports vereinfachen das Deployment, erfordern aber pfadbasiertes Routing (/socket.io) bei Verwendung von Reverse Proxies.

Wie testet man WebSocket Gateways in NestJS?

NestJS Test-Utilities unterstützen Gateway-Tests durch Test.createTestingModule(). Die socket.io-client-Bibliothek verbindet sich mit dem Testserver. Lifecycle-Hooks und Message-Handler werden getestet, indem Events emittiert und Antworten oder Seiteneffekte überprüft werden.

chat.gateway.spec.tstypescript
import { Test } from '@nestjs/testing';
import { INestApplication } from '@nestjs/common';
import { io, Socket } from 'socket.io-client';
import { ChatGateway } from './chat.gateway';

describe('ChatGateway', () => {
  let app: INestApplication;
  let client: Socket;

  beforeAll(async () => {
    const module = await Test.createTestingModule({
      providers: [ChatGateway],
    }).compile();

    app = module.createNestApplication();
    await app.listen(3000);
    client = io('http://localhost:3000');
  });

  afterAll(async () => {
    client.disconnect();
    await app.close();
  });

  it('receives message acknowledgment', (done) => {
    client.emit('message', { text: 'test', room: 'lobby' });
    client.on('message', (data) => {
      expect(data.text).toBe('test');
      done();
    });
  });
});

Wann sollte der ws-Adapter anstelle von Socket.IO verwendet werden?

Der ws-Bibliothek-Adapter (@nestjs/platform-ws) bietet geringeren Overhead für Anwendungen, die Socket.IO-Features wie automatische Wiederverbindung, Rooms oder Fallback-Transporte nicht benötigen. Hochfrequenz-Handelssysteme und Spieleserver bevorzugen oft ws für reduzierte Latenz.

Für breitere NestJS-Architekturkonzepte behandelt der verwandte Artikel zu Guards, Interceptors und Modulare Architektur, wie diese Muster über HTTP- und WebSocket-Kontexte hinweg integriert werden.

Fazit

  • WebSocket Gateways integrieren sich mit NestJS Dependency Injection, Guards und Filtern für konsistente Muster über HTTP- und Echtzeit-Endpunkte hinweg
  • Lifecycle Hooks (OnGatewayConnection, OnGatewayDisconnect) verwalten Präsenzverfolgung und Ressourcenbereinigung
  • Authentifizierungsabläufe unterscheiden sich von HTTP; Token-Validierung erfolgt während des Handshakes oder durch dedizierte WebSocket Guards
  • Room-basiertes Broadcasting mit Socket.IO ermöglicht gezielte Nachrichtenübermittlung ohne manuelle Verwaltung von Socket-Listen
  • Redis-Adapter löst horizontale Skalierung durch Synchronisierung von Events über mehrere Server-Instanzen
  • Exception Filter erfordern WebSocket-spezifische Implementierungen mit WsException und benutzerdefinierten Filtern

Fang an zu üben!

Teste dein Wissen mit unseren Interview-Simulatoren und technischen Tests.

Anthony Fillion-Maillet

Geschrieben von

Anthony Fillion-Maillet

Fullstack-Entwickler, Gründer von SharpSkill

Seit über 10 Jahren Fullstack-Entwickler. Er leitet SharpSkill und verantwortet alles, was hier erscheint.

Aktualisiert am 10. August 2026

Teilen

Verwandte Artikel