NestJS та WebSockets у 2026: Комунікація в Реальному Часі, Gateway та Питання на Співбесідах
Повний посібник по WebSockets у NestJS з патерном Gateway, інтеграцією Socket.IO, автентифікацією, обробкою помилок та питаннями на співбесідах 2026 року.

NestJS WebSockets пропонують структурований підхід до комунікації в реальному часі з використанням патерну Gateway. На відміну від сирих імплементацій WebSocket, NestJS абстрагує складність через декоратори та безшовно інтегрується з системою впровадження залежностей.
WebSocket Gateway у NestJS — це клас, позначений декоратором @WebSocketGateway(), який керує двонаправленою комунікацією між клієнтом і сервером. Він підтримує кілька адаптерів (Socket.IO, ws) та інтегрується з Guards, Pipes та Interceptors у NestJS.
Налаштування WebSocket Gateway з Socket.IO
Стандартний адаптер у NestJS використовує Socket.IO, який забезпечує автоматичне перепідключення, підтримку кімнат та fallback до HTTP long-polling. Встановлення вимагає пакету, специфічного для платформи, разом з основним модулем WebSockets.
# terminal
npm install @nestjs/websockets @nestjs/platform-socket.io socket.ioБазовий gateway прослуховує вхідні повідомлення та може розсилати відповіді підключеним клієнтам.
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 пов'язує метод з конкретною назвою події. @MessageBody() витягує payload, тоді як @ConnectedSocket() надає доступ до сокету клієнта для цілеспрямованих відповідей.
Хуки Життєвого Циклу для Керування З'єднаннями
Gateway NestJS імплементують інтерфейси життєвого циклу для обробки підключень та відключень клієнтів. Ці хуки дозволяють очищення ресурсів, відстеження присутності та валідацію з'єднань.
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}`);
}
}Три інтерфейси життєвого циклу служать різним цілям: OnGatewayInit виконується один раз при старті, OnGatewayConnection спрацьовує при кожному підключенні клієнта, а OnGatewayDisconnect обробляє очищення, коли клієнти від'єднуються.
Автентифікація з WebSocket Guards
WebSocket з'єднання вимагають валідації автентифікації перед наданням доступу до захищених подій. NestJS Guards працюють з gateway, хоча контекст виконання відрізняється від HTTP запитів. Офіційна документація NestJS WebSockets детально описує інтеграцію guards.
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 застосовується до класу gateway або окремих обробників повідомлень за допомогою декоратора @UseGuards(). Клас WsException кидає помилки, які клієнт отримує через подію error Socket.IO.
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
}
}Для питань автентифікації на рівні модуля варто ознайомитися з модулем питань на співбесідах NestJS про автентифікацію, що охоплює стратегії JWT та керування сесіями.
Готовий до співбесід з Node.js / NestJS?
Практикуйся з нашими інтерактивними симуляторами, flashcards та технічними тестами.
Патерни Розсилки на Основі Кімнат
Кімнати Socket.IO дозволяють цілеспрямовану доставку повідомлень підмножинам підключених клієнтів. Типові випадки використання включають чат-кімнати, ігрові лобі та функції живої співпраці.
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() та server.to(room).emit() важлива: перший виключає відправника, тоді як другий включає всіх членів кімнати.
Обробка Помилок з Фільтрами Винятків
Винятки WebSocket вимагають спеціальних фільтрів, оскільки фільтри винятків HTTP не застосовуються до контекстів gateway. Власні фільтри перехоплюють WsException та форматують відповіді з помилками для клієнтів.
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(),
});
}
}Фільтри застосовуються на рівні gateway для консистентної обробки помилок у всіх обробниках повідомлень.
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
}Цей патерн відображає філософію NestJS щодо декораторів та фільтрів, описану в модулі middleware та interceptors.
Масштабування WebSockets з Redis Адаптером
Розгортання WebSocket на одному сервері виходять з ладу, коли балансування навантаження розподіляє клієнтів між кількома інстансами. Redis адаптер Socket.IO синхронізує події між інстансами через механізм pub/sub.
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 {}Потім gateway використовує адаптер для комунікації між інстансами.
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 адаптером повідомлення, відправлене на одному інстансі сервера, досягає клієнтів, підключених до будь-якого інстансу в кластері.
Поширені Питання на Співбесідах про NestJS WebSockets
Технічні співбесіди часто перевіряють розуміння архітектурних рішень для реального часу та деталей імплементації, специфічних для NestJS.
Як NestJS обробляє автентифікацію WebSocket інакше, ніж HTTP?
HTTP middleware не виконується для WebSocket з'єднань. Автентифікація відбувається під час фази handshake або через Guards, застосовані до gateway. Валідація токенів зазвичай відбувається в handleConnection() або в кастомному Guard, який читає з socket.handshake.auth.
Яка різниця між конфігурацією порту @WebSocketGateway() та основним портом додатку?
За замовчуванням WebSocket gateway поділяють порт HTTP сервера. Вказівка порту в @WebSocketGateway(3001) створює окремий WebSocket сервер на цьому порту. Спільні порти спрощують розгортання, але вимагають маршрутизації на основі шляхів (/socket.io) при використанні reverse proxy.
Як тестувати WebSocket gateway в NestJS?
Інструменти тестування NestJS підтримують тестування gateway через Test.createTestingModule(). Бібліотека socket.io-client підключається до тестового сервера. Хуки життєвого циклу та обробники повідомлень тестуються шляхом емісії подій та перевірки відповідей або побічних ефектів.
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();
});
});
});Коли слід використовувати адаптер ws замість Socket.IO?
Адаптер бібліотеки ws (@nestjs/platform-ws) пропонує менший overhead для додатків, яким не потрібні функції Socket.IO, такі як автоматичне перепідключення, кімнати чи fallback транспорти. Системи високочастотної торгівлі та ігрові сервери часто віддають перевагу ws через зменшену затримку.
Для ширших концепцій архітектури NestJS, пов'язана стаття про Guards, Interceptors та Модульну Архітектуру описує, як ці патерни інтегруються в контекстах HTTP та WebSocket.
Висновок
- WebSocket Gateways інтегруються з dependency injection NestJS, Guards та Filters для консистентних патернів у HTTP та real-time endpoints
- Хуки життєвого циклу (
OnGatewayConnection,OnGatewayDisconnect) керують відстеженням присутності та очищенням ресурсів - Потоки автентифікації відрізняються від HTTP; валідація токенів відбувається під час handshake або через спеціалізовані WebSocket Guards
- Розсилка на основі кімнат з Socket.IO дозволяє цілеспрямовані повідомлення без ручного керування списками сокетів
- Redis адаптер вирішує горизонтальне масштабування шляхом синхронізації подій між кількома інстансами сервера
- Фільтри винятків вимагають імплементацій, специфічних для WebSocket, з використанням
WsExceptionта кастомних фільтрів
Починай практикувати!
Перевір свої знання з нашими симуляторами співбесід та технічними тестами.

Автор:
Anthony Fillion-MailletFullstack-розробник, засновник SharpSkill
Fullstack-розробник понад 10 років. Керує SharpSkill і відповідає за все, що тут публікується.
Оновлено 10 серпня 2026 р.
Теги
Поділитися
Пов'язані статті

NestJS та GraphQL у 2026: Схеми, Резолвери та Питання на Співбесіді
Повний посібник з інтеграції NestJS GraphQL: підходи schema-first та code-first, резолвери, DataLoader та питання на технічних співбесідах 2026 року.

Співбесіда NestJS: Guards, Interceptors і модульна архітектура
Часті питання технічних співбесід з NestJS щодо Guards, Interceptors і модульної архітектури з конкретними прикладами коду TypeScript і технічними поясненнями.

NestJS + Prisma: сучасний бекенд-стек для Node.js
Повний посібник зі створення сучасного бекенд-API з NestJS і Prisma. Налаштування, моделі, сервіси, транзакції та найкращі практики.