NestJS en WebSockets in 2026: Real-Time Communicatie, Gateway en Sollicitatievragen

WebSockets in NestJS beheersen met Gateway-patronen, Socket.IO-integratie, authenticatie, foutafhandeling en veelgestelde sollicitatievragen voor 2026.

NestJS WebSocket real-time communicatie gateway

NestJS WebSockets bieden een gestructureerde aanpak voor real-time communicatie met behulp van het Gateway-patroon. In tegenstelling tot ruwe WebSocket-implementaties abstraheert NestJS de complexiteit door middel van decorators en integreert het naadloos met het dependency injection-systeem.

Snelle Definitie

Een WebSocket Gateway in NestJS is een klasse die is gedecoreerd met @WebSocketGateway() en bidirectionele communicatie tussen client en server afhandelt. Het ondersteunt meerdere adapters (Socket.IO, ws) en integreert met NestJS Guards, Pipes en Interceptors.

Een WebSocket Gateway Opzetten met Socket.IO

De standaard adapter in NestJS gebruikt Socket.IO, dat automatische herverbinding, room-ondersteuning en fallback naar HTTP long-polling biedt. De installatie vereist het platformspecifieke pakket naast de core WebSockets-module.

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

Een basis gateway luistert naar inkomende berichten en kan antwoorden broadcasten naar verbonden clients.

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(),
    });
  }
}

De @SubscribeMessage-decorator bindt een methode aan een specifieke eventnaam. @MessageBody() extraheert de payload, terwijl @ConnectedSocket() toegang biedt tot de client socket voor gerichte antwoorden.

Lifecycle Hooks voor Verbindingsbeheer

NestJS gateways implementeren lifecycle-interfaces voor het afhandelen van client-verbindingen en -disconnecties. Deze hooks maken resource cleanup, aanwezigheidstracking en verbindingsvalidatie mogelijk.

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}`);
  }
}

De drie lifecycle-interfaces hebben verschillende doeleinden: OnGatewayInit wordt eenmalig uitgevoerd bij opstarten, OnGatewayConnection wordt geactiveerd per client-verbinding, en OnGatewayDisconnect handelt cleanup af wanneer clients vertrekken.

Authenticatie met WebSocket Guards

WebSocket-verbindingen vereisen authenticatievalidatie voordat toegang tot beschermde events wordt verleend. NestJS Guards werken met gateways, hoewel de uitvoeringscontext verschilt van HTTP-verzoeken. De officiële NestJS WebSockets-documentatie behandelt guard-integratie in 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');
    }
  }
}

Pas de guard toe op de gateway-klasse of individuele message handlers met behulp van de @UseGuards()-decorator. De WsException-klasse gooit fouten die de client ontvangt via het Socket.IO error event.

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
  }
}

Voor vragen over authenticatie op moduleniveau biedt de NestJS authenticatie interview module informatie over JWT-strategieën en sessiebeheer.

Klaar om je Node.js / NestJS gesprekken te halen?

Oefen met onze interactieve simulatoren, flashcards en technische tests.

Room-gebaseerde Broadcasting Patronen

Socket.IO rooms maken gerichte berichtbezorging naar subsets van verbonden clients mogelijk. Veelvoorkomende use cases zijn chatrooms, game lobbies en live samenwerkingsfuncties.

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);
  }
}

Het onderscheid tussen client.to(room).emit() en server.to(room).emit() is belangrijk: de eerste sluit de verzender uit, terwijl de laatste alle room-leden omvat.

Foutafhandeling met Exception Filters

WebSocket-excepties vereisen speciale filters omdat HTTP exception filters niet van toepassing zijn op gateway-contexten. Aangepaste filters vangen WsException af en formatteren foutresponses voor 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(),
    });
  }
}

Pas filters toe op gateway-niveau voor consistente foutafhandeling over alle message handlers.

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
}

Dit patroon weerspiegelt de NestJS-filosofie van decorators en filters die wordt beschreven in de middleware en interceptors module.

WebSockets Schalen met Redis Adapter

Single-server WebSocket deployments falen wanneer load balancing clients over meerdere instanties distribueert. De Socket.IO Redis adapter synchroniseert events over instanties via een pub/sub-mechanisme.

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 {}

De gateway gebruikt vervolgens de adapter voor cross-instance communicatie.

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);
  }
}

Met de Redis adapter bereikt een bericht dat op één server-instantie wordt uitgezonden, clients die verbonden zijn met elke instantie in het cluster.

Veelgestelde Sollicitatievragen over NestJS WebSockets

Technische sollicitatiegesprekken peilen vaak naar begrip van real-time architectuurbeslissingen en NestJS-specifieke implementatiedetails.

Veelgestelde Vraag

Hoe behandelt NestJS WebSocket-authenticatie anders dan HTTP?

HTTP middleware wordt niet uitgevoerd voor WebSocket-verbindingen. Authenticatie vindt plaats tijdens de handshake-fase of via Guards die op de gateway worden toegepast. Token-validatie gebeurt doorgaans in handleConnection() of een aangepaste Guard die leest uit socket.handshake.auth.

Wat is het verschil tussen de poortconfiguratie van @WebSocketGateway() en de hoofdapplicatiepoort?

Standaard delen WebSocket Gateways de HTTP-serverpoort. Het specificeren van een poort in @WebSocketGateway(3001) creëert een aparte WebSocket-server op die poort. Gedeelde poorten vereenvoudigen deployment maar vereisen pad-gebaseerde routing (/socket.io) bij gebruik van reverse proxies.

Hoe test je WebSocket Gateways in NestJS?

NestJS testing utilities ondersteunen gateway-testing via Test.createTestingModule(). De socket.io-client bibliotheek verbindt met de testserver. Lifecycle hooks en message handlers worden getest door events te emitteren en te asserteren op responses of side effects.

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();
    });
  });
});

Wanneer moet je de ws adapter gebruiken in plaats van Socket.IO?

De ws library adapter (@nestjs/platform-ws) biedt lagere overhead voor applicaties die Socket.IO-features zoals automatische herverbinding, rooms of fallback transports niet nodig hebben. High-frequency trading systemen en game servers geven vaak de voorkeur aan ws voor verminderde latency.

Voor bredere NestJS-architectuurconcepten behandelt het gerelateerde artikel over Guards, Interceptors en Modulaire Architectuur hoe deze patronen integreren over HTTP- en WebSocket-contexten.

Conclusie

  • WebSocket Gateways integreren met NestJS dependency injection, Guards en Filters voor consistente patronen over HTTP- en real-time endpoints
  • Lifecycle hooks (OnGatewayConnection, OnGatewayDisconnect) beheren aanwezigheidstracking en resource cleanup
  • Authenticatiestromen verschillen van HTTP; token-validatie vindt plaats tijdens de handshake of via speciale WebSocket Guards
  • Room-gebaseerde broadcasting met Socket.IO maakt gerichte messaging mogelijk zonder handmatig socket-lijsten te beheren
  • Redis adapter lost horizontale schaalbaarheid op door events te synchroniseren over meerdere server-instanties
  • Exception filters vereisen WebSocket-specifieke implementaties met WsException en aangepaste filters

Begin met oefenen!

Test je kennis met onze gespreksimulatoren en technische tests.

Anthony Fillion-Maillet

Geschreven door

Anthony Fillion-Maillet

Fullstack-ontwikkelaar, oprichter van SharpSkill

Al meer dan 10 jaar fullstack-ontwikkelaar. Hij leidt SharpSkill en staat in voor alles wat hier verschijnt.

Bijgewerkt op 10 augustus 2026

Delen

Gerelateerde artikelen