Как реализовать WebSockets в NestJS?

MiddleNestJS · Backend·Обновлено 11 августа 2026
Коротко
В NestJS WebSockets реализуются через декоратор @WebSocketGateway и класс-шлюз с методами, помеченными @SubscribeMessage. NestJS абстрагирует транспортный слой через адаптеры, поддерживая socket.io и нативные ws.

WebSockets в NestJS

NestJS предоставляет встроенную поддержку WebSocket-соединений через модуль @nestjs/websockets. Основная абстракция — Gateway (шлюз), который аналогичен контроллеру, но работает с событийной моделью вместо HTTP-запросов.

Установка зависимостей

Для работы с socket.io (наиболее распространённый вариант):

npm install @nestjs/websockets @nestjs/platform-socket.io socket.io

Для нативных WebSocket без socket.io:

npm install @nestjs/websockets @nestjs/platform-ws ws

Создание Gateway

Gateway — это класс, помеченный декоратором @WebSocketGateway(). Он может принимать порт и опции, включая namespace и CORS-настройки.

Жизненный цикл и интерфейсы

Gateway реализует интерфейсы:

  • OnGatewayInit — вызывается после инициализации (afterInit)
  • OnGatewayConnection — вызывается при подключении клиента (handleConnection)
  • OnGatewayDisconnect — вызывается при отключении (handleDisconnect)

Отправка сообщений

Для отправки событий всем подключённым клиентам используется декоратор @WebSocketServer(), который инжектирует объект сервера. Метод server.emit() транслирует событие всем клиентам.

Для ответа только отправителю метод с @SubscribeMessage может возвращать объект { event, data } или использовать client.emit().

Интеграция с модульной системой

Gateway регистрируется в providers модуля так же, как сервис. Он может инжектировать другие сервисы через конструктор.

Namespace и Room

Socket.io-адаптер поддерживает namespace через @WebSocketGateway({ namespace: '/chat' }) и комнаты через client.join('room-name') / server.to('room-name').emit().

Guards, Pipes и Interceptors

WebSocket Gateway поддерживает стандартные механизмы NestJS: @UseGuards(), @UsePipes(), @UseInterceptors(). Это позволяет переиспользовать логику авторизации и валидации из HTTP-части приложения.

Адаптеры

По умолчанию NestJS использует socket.io адаптер. Для замены на нативный ws нужно в main.ts вызвать app.useWebSocketAdapter(new WsAdapter(app)).

Что хочет услышать интервьюер

Знание декоратора @WebSocketGateway и его параметров (порт, namespace, cors)

Понимание @SubscribeMessage для обработки входящих событий и @WebSocketServer для доступа к серверу

Знание lifecycle-интерфейсов: OnGatewayConnection, OnGatewayDisconnect, OnGatewayInit

Умение интегрировать Gateway в модульную систему NestJS (регистрация в providers)

Понимание разницы между адаптерами socket.io и ws, и когда применять каждый

Пример: Базовый Gateway с socket.io

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

@WebSocketGateway({
  cors: { origin: '*' }, // разрешаем подключения с любого origin
  namespace: '/chat',
})
export class ChatGateway implements OnGatewayConnection, OnGatewayDisconnect {
  @WebSocketServer()
  server: Server; // инжектируем объект сервера socket.io

  handleConnection(client: Socket) {
    console.log(`Клиент подключился: ${client.id}`);
  }

  handleDisconnect(client: Socket) {
    console.log(`Клиент отключился: ${client.id}`);
  }

  @SubscribeMessage('sendMessage')
  handleMessage(
    @MessageBody() data: { room: string; text: string },
    @ConnectedSocket() client: Socket,
  ): void {
    // транслируем сообщение всем в комнате, кроме отправителя
    client.to(data.room).emit('newMessage', {
      from: client.id,
      text: data.text,
    });
  }

  @SubscribeMessage('joinRoom')
  handleJoinRoom(
    @MessageBody() room: string,
    @ConnectedSocket() client: Socket,
  ): void {
    client.join(room);
    // уведомляем всех в комнате о новом участнике
    this.server.to(room).emit('userJoined', { userId: client.id });
  }
}

Пример: Регистрация Gateway в модуле

import { Module } from '@nestjs/common';
import { ChatGateway } from './chat.gateway';
import { ChatService } from './chat.service';

@Module({
  providers: [ChatGateway, ChatService], // Gateway регистрируется как провайдер
})
export class ChatModule {}

Пример: Gateway с инжекцией сервиса и авторизацией через Guard

import { UseGuards } from '@nestjs/common';
import {
  WebSocketGateway,
  WebSocketServer,
  SubscribeMessage,
  MessageBody,
} from '@nestjs/websockets';
import { Server } from 'socket.io';
import { WsJwtGuard } from '../auth/ws-jwt.guard';
import { ChatService } from './chat.service';

@WebSocketGateway({ cors: { origin: '*' } })
export class ChatGateway {
  @WebSocketServer()
  server: Server;

  constructor(private readonly chatService: ChatService) {}

  @UseGuards(WsJwtGuard) // защищаем событие JWT-гвардом
  @SubscribeMessage('privateMessage')
  async handlePrivateMessage(
    @MessageBody() payload: { to: string; text: string },
  ): Promise<void> {
    const saved = await this.chatService.saveMessage(payload);
    // отправляем сообщение конкретному сокету по id
    this.server.to(payload.to).emit('privateMessage', saved);
  }
}

Типичные ошибки

Забывают зарегистрировать Gateway в providers модуля — шлюз не поднимается

Путают порт Gateway с портом HTTP-сервера: по умолчанию Gateway слушает отдельный порт, что вызывает CORS-проблемы

Не реализуют OnGatewayDisconnect и не чистят ресурсы (комнаты, активные сессии) при отключении клиента

Используют server.emit() внутри синхронного кода без ожидания готовности сервера вместо afterInit

Смешивают нативный WebSocket API (ws) с socket.io-клиентом на фронтенде — они несовместимы

Лучшие курсы по теме

изображение курса

Docker и Ansible

Антон Ларичев
AI-тренажерыAI-тренажеры
Гарантия
Бонусы
иконка звёздочки рейтинга4.7
3 999 ₽ 6 990 ₽
Подробнее
изображение курса

Node.js с нуля

Антон Ларичев
AI-тренажерыAI-тренажеры
Практика в студииПрактика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.8
3 999 ₽ 6 990 ₽
Подробнее
изображение курса

Nest.js с нуля

Антон Ларичев
AI-тренажерыAI-тренажеры
Практика в студииПрактика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.6
3 999 ₽ 6 990 ₽
Подробнее