2026'da NestJS ve WebSockets: Gerçek Zamanlı İletişim, Gateway ve Mülakat Soruları

NestJS'te WebSockets için kapsamlı rehber: Gateway deseni, Socket.IO entegrasyonu, kimlik doğrulama, hata yönetimi ve 2026 mülakat soruları.

2026'da NestJS ve WebSockets

NestJS WebSockets, Gateway deseni kullanarak gerçek zamanlı iletişime yapısal bir yaklaşım sunar. Ham WebSocket uygulamalarının aksine, NestJS dekoratörler aracılığıyla karmaşıklığı soyutlar ve bağımlılık enjeksiyonu sistemiyle sorunsuz bir şekilde entegre olur.

Hızlı Tanım

NestJS'te WebSocket Gateway, @WebSocketGateway() dekoratörüyle işaretlenmiş, istemci ve sunucu arasında çift yönlü iletişimi yöneten bir sınıftır. Birden fazla adaptörü (Socket.IO, ws) destekler ve NestJS Guards, Pipes ve Interceptors ile entegre çalışır.

Socket.IO ile WebSocket Gateway Kurulumu

NestJS'teki varsayılan adaptör, otomatik yeniden bağlanma, oda desteği ve HTTP long-polling'e fallback sağlayan Socket.IO kullanır. Kurulum, ana WebSockets modülünün yanı sıra platforma özgü paketi gerektirir.

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

Temel bir gateway, gelen mesajları dinler ve bağlı istemcilere yanıtları yayınlayabilir.

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

@SubscribeMessage dekoratörü, bir metodu belirli bir olay adına bağlar. @MessageBody() payload'ı çıkarırken, @ConnectedSocket() hedefli yanıtlar için istemci soketine erişim sağlar.

Bağlantı Yönetimi için Yaşam Döngüsü Hook'ları

NestJS gateway'leri, istemci bağlantılarını ve bağlantı kesintilerini yönetmek için yaşam döngüsü arayüzlerini uygular. Bu hook'lar kaynak temizleme, varlık takibi ve bağlantı doğrulamasını mümkün kılar.

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

Üç yaşam döngüsü arayüzü farklı amaçlara hizmet eder: OnGatewayInit başlangıçta bir kez çalışır, OnGatewayConnection her istemci bağlantısında tetiklenir ve OnGatewayDisconnect istemciler ayrıldığında temizliği yönetir.

WebSocket Guards ile Kimlik Doğrulama

WebSocket bağlantıları, korunan olaylara erişime izin vermeden önce kimlik doğrulama kontrolü gerektirir. NestJS Guards gateway'lerle çalışır, ancak yürütme bağlamı HTTP isteklerinden farklıdır. Resmi NestJS WebSockets dokümantasyonu guard entegrasyonunu ayrıntılı olarak kapsar.

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

Guard, @UseGuards() dekoratörü kullanılarak gateway sınıfına veya bireysel mesaj işleyicilerine uygulanır. WsException sınıfı, istemcinin Socket.IO hata olayı aracılığıyla aldığı hataları fırlatır.

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

Modül düzeyinde kimlik doğrulama soruları için JWT stratejileri ve oturum yönetimini kapsayan NestJS kimlik doğrulama mülakat modülünü inceleyin.

Node.js / NestJS mülakatlarında başarılı olmaya hazır mısın?

İnteraktif simülatörler, flashcards ve teknik testlerle pratik yap.

Oda Tabanlı Yayın Desenleri

Socket.IO odaları, bağlı istemcilerin alt kümelerine hedefli mesaj teslimatını mümkün kılar. Yaygın kullanım durumları arasında sohbet odaları, oyun lobileri ve canlı işbirliği özellikleri bulunur.

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

client.to(room).emit() ve server.to(room).emit() arasındaki fark önemlidir: ilki göndericiyi hariç tutarken, ikincisi tüm oda üyelerini dahil eder.

İstisna Filtreleri ile Hata Yönetimi

WebSocket istisnaları, HTTP istisna filtreleri gateway bağlamlarına uygulanmadığından özel filtreler gerektirir. Özel filtreler WsException'ı yakalar ve istemciler için hata yanıtlarını biçimlendirir.

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

Filtreler, tüm mesaj işleyicilerinde tutarlı hata yönetimi için gateway düzeyinde uygulanır.

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
}

Bu desen, middleware ve interceptors modülünde açıklanan dekoratörler ve filtreler hakkındaki NestJS felsefesini yansıtır.

Redis Adaptör ile WebSockets'i Ölçeklendirme

Tek sunuculu WebSocket dağıtımları, yük dengeleme istemcileri birden fazla örneğe dağıttığında başarısız olur. Socket.IO Redis adaptörü pub/sub mekanizması aracılığıyla örnekler arasında olayları senkronize eder.

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

Ardından gateway, örnek arası iletişim için adaptörü kullanır.

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

Redis adaptörü ile bir sunucu örneğinde yayınlanan mesaj, kümedeki herhangi bir örneğe bağlı istemcilere ulaşır.

NestJS WebSockets Hakkında Yaygın Mülakat Soruları

Teknik mülakatlar genellikle gerçek zamanlı mimari kararları ve NestJS'e özgü uygulama detayları hakkındaki anlayışı sorgular.

Sıkça Sorulanlar

NestJS, WebSocket kimlik doğrulamasını HTTP'den nasıl farklı yönetir?

HTTP middleware, WebSocket bağlantıları için çalışmaz. Kimlik doğrulama, el sıkışma aşamasında veya gateway'e uygulanan Guards aracılığıyla gerçekleşir. Token doğrulaması genellikle handleConnection()'da veya socket.handshake.auth'dan okuyan özel bir Guard'da yapılır.

@WebSocketGateway() port yapılandırması ile ana uygulama portu arasındaki fark nedir?

Varsayılan olarak WebSocket gateway'leri HTTP sunucu portunu paylaşır. @WebSocketGateway(3001) içinde port belirtmek, o portta ayrı bir WebSocket sunucusu oluşturur. Paylaşılan portlar dağıtımı basitleştirir ancak reverse proxy kullanırken yol tabanlı yönlendirme (/socket.io) gerektirir.

NestJS'te WebSocket gateway'leri nasıl test edilir?

NestJS test araçları, Test.createTestingModule() aracılığıyla gateway testini destekler. socket.io-client kütüphanesi test sunucusuna bağlanır. Yaşam döngüsü hook'ları ve mesaj işleyicileri, olaylar yayınlanarak ve yanıtlar veya yan etkiler üzerinde doğrulamalar yapılarak test edilir.

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

Socket.IO yerine ws adaptörü ne zaman kullanılmalıdır?

ws kütüphanesi adaptörü (@nestjs/platform-ws), otomatik yeniden bağlanma, odalar veya fallback taşımaları gibi Socket.IO özelliklerine ihtiyaç duymayan uygulamalar için daha düşük ek yük sunar. Yüksek frekanslı ticaret sistemleri ve oyun sunucuları, azaltılmış gecikme için genellikle ws'i tercih eder.

Daha geniş NestJS mimari kavramları için, bu desenlerin HTTP ve WebSocket bağlamlarında nasıl entegre olduğunu kapsayan Guards, Interceptors ve Modüler Mimari makalesine bakın.

Sonuç

  • WebSocket Gateway'ler, HTTP ve gerçek zamanlı endpoint'lerde tutarlı desenler için NestJS bağımlılık enjeksiyonu, Guards ve Filters ile entegre olur
  • Yaşam döngüsü hook'ları (OnGatewayConnection, OnGatewayDisconnect) varlık takibi ve kaynak temizliğini yönetir
  • Kimlik doğrulama akışları HTTP'den farklıdır; token doğrulaması el sıkışma sırasında veya özel WebSocket Guards aracılığıyla gerçekleşir
  • Socket.IO ile oda tabanlı yayın, soket listelerini manuel olarak yönetmeden hedefli mesajlaşmayı mümkün kılar
  • Redis adaptörü, birden fazla sunucu örneği arasında olayları senkronize ederek yatay ölçeklendirmeyi çözer
  • İstisna filtreleri, WsException ve özel filtreler kullanarak WebSocket'e özgü uygulamalar gerektirir

Pratik yapmaya başla!

Mülakat simülatörleri ve teknik testlerle bilgini test et.

Anthony Fillion-Maillet

Yazan:

Anthony Fillion-Maillet

Fullstack geliştirici, SharpSkill kurucusu

10 yılı aşkın süredir fullstack geliştirici. SharpSkill’i yönetiyor ve burada yayımlanan her şeyden sorumlu.

10 Ağustos 2026 tarihinde güncellendi

Etiketler

#nestjs
#websockets
#real-time
#socket.io
#gateway

Paylaş

İlgili makaleler