NestJS实战:从零搭建WebSocket实时通信系统

基础环境准备

在构建WebSocket通信系统前,需完成基础环境搭建。首先通过npm安装核心依赖包:

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

这些包分别提供WebSocket网关支持、Socket.IO平台适配及底层通信能力。其中@nestjs/websockets是NestJS官方提供的WebSocket模块,socket.io作为底层通信库,两者结合可实现跨浏览器兼容的实时通信。

核心网关实现

WebSocket通信的核心逻辑集中在Gateway类中,以下通过分步骤实现完整功能:

1. 创建网关类

  1. import {
  2. WebSocketGateway,
  3. WebSocketServer,
  4. SubscribeMessage,
  5. MessageBody,
  6. ConnectedSocket,
  7. OnGatewayInit,
  8. OnGatewayConnection,
  9. OnGatewayDisconnect
  10. } from '@nestjs/websockets';
  11. import { Server, Socket } from 'socket.io';
  12. @WebSocketGateway({
  13. namespace: '/chat',
  14. cors: {
  15. origin: '*', // 生产环境应配置具体域名
  16. methods: ['GET', 'POST']
  17. }
  18. })
  19. export class ChatGateway implements
  20. OnGatewayInit,
  21. OnGatewayConnection,
  22. OnGatewayDisconnect
  23. {
  24. @WebSocketServer()
  25. server: Server;
  26. // 初始化回调
  27. afterInit(server: Server) {
  28. console.log('WebSocket Server Initialized', server.engine.clientsCount);
  29. }
  30. // 连接建立处理
  31. handleConnection(client: Socket) {
  32. console.log(`Client connected: ${client.id}`);
  33. // 可在此处实现认证逻辑
  34. }
  35. // 连接断开处理
  36. handleDisconnect(client: Socket) {
  37. console.log(`Client disconnected: ${client.id}`);
  38. }
  39. }

关键配置说明:

  • namespace:实现逻辑隔离,不同命名空间可承载不同业务场景
  • cors:跨域配置,开发阶段可设为通配符,生产环境需严格限制
  • 生命周期接口:OnGatewayInit等接口提供标准化的事件处理机制

2. 消息处理实现

通过@SubscribeMessage装饰器定义消息处理器:

  1. @SubscribeMessage('sendMessage')
  2. handleMessage(
  3. @MessageBody() data: { user: string; message: string },
  4. @ConnectedSocket() client: Socket
  5. ) {
  6. console.log(`Received message from ${data.user}: ${data.message}`);
  7. // 广播消息给所有客户端(除发送者)
  8. client.broadcast.emit('receiveMessage', {
  9. ...data,
  10. timestamp: new Date().toISOString()
  11. });
  12. // 若需包含发送者,使用:
  13. // this.server.emit('receiveMessage', {...data});
  14. }

消息处理最佳实践:

  1. 数据结构标准化:建议定义DTO类进行数据校验
  2. 错误处理:添加try-catch块捕获异常
  3. 性能优化:避免在处理器中执行耗时操作

模块集成与注册

创建独立模块管理WebSocket相关依赖:

  1. import { Module } from '@nestjs/common';
  2. import { ChatGateway } from './chat.gateway';
  3. @Module({
  4. providers: [ChatGateway],
  5. exports: [ChatGateway] // 如需在其他模块使用
  6. })
  7. export class ChatModule {}

在主模块中导入该模块:

  1. import { Module } from '@nestjs/common';
  2. import { ChatModule } from './chat/chat.module';
  3. @Module({
  4. imports: [ChatModule],
  5. // ...其他配置
  6. })
  7. export class AppModule {}

客户端集成实现

浏览器端实现分为连接建立、事件监听和消息发送三部分:

1. 基础连接

  1. const socket = io('http://localhost:3000/chat', {
  2. transports: ['websocket'], // 优先使用WebSocket
  3. reconnection: true, // 自动重连
  4. reconnectionAttempts: 5, // 重试次数
  5. reconnectionDelay: 1000 // 重试间隔
  6. });

2. 事件处理

  1. // 连接状态监听
  2. socket.on('connect', () => {
  3. console.log('Connection established', socket.id);
  4. });
  5. socket.on('disconnect', (reason) => {
  6. console.log('Disconnected:', reason);
  7. });
  8. // 消息接收处理
  9. socket.on('receiveMessage', (data) => {
  10. const messageElement = document.createElement('div');
  11. messageElement.innerHTML = `<strong>${data.user}:</strong> ${data.message}`;
  12. document.getElementById('messages').appendChild(messageElement);
  13. });

3. 消息发送

  1. document.getElementById('send-btn').addEventListener('click', () => {
  2. const user = '当前用户'; // 实际应从登录状态获取
  3. const message = document.getElementById('message-input').value;
  4. socket.emit('sendMessage', { user, message }, (ack) => {
  5. console.log('Server acknowledgement:', ack);
  6. });
  7. });

高级功能扩展

1. 房间管理实现

  1. // 加入房间
  2. @SubscribeMessage('joinRoom')
  3. handleJoinRoom(
  4. @MessageBody() { roomId }: { roomId: string },
  5. @ConnectedSocket() client: Socket
  6. ) {
  7. client.join(roomId);
  8. client.emit('roomJoined', { roomId });
  9. }
  10. // 房间内广播
  11. @SubscribeMessage('roomMessage')
  12. handleRoomMessage(
  13. @MessageBody() { roomId, ...data }: { roomId: string; user: string; message: string },
  14. @ConnectedSocket() client: Socket
  15. ) {
  16. client.to(roomId).emit('roomMessageReceived', data);
  17. }

2. 认证中间件

  1. @WebSocketGateway({
  2. middleware: [authMiddleware] // 自定义中间件
  3. })
  4. export class SecureChatGateway {
  5. // ...其他配置
  6. }
  7. // 中间件示例
  8. const authMiddleware = (socket: Socket, next: (err?: any) => void) => {
  9. const token = socket.handshake.auth.token;
  10. if (verifyToken(token)) {
  11. return next();
  12. }
  13. next(new Error('Unauthorized'));
  14. };

生产环境优化建议

  1. 连接管理:实现心跳机制检测连接状态
  2. 消息限流:防止客户端频繁发送消息
  3. 负载均衡:使用Redis适配器实现多实例通信
  4. 监控告警:集成日志服务跟踪连接状态
  5. 安全加固:配置HTTPS、设置合理的CORS策略

完整项目结构

  1. src/
  2. ├── chat/
  3. ├── chat.gateway.ts
  4. ├── chat.module.ts
  5. └── dto/ # 数据传输对象
  6. ├── app.module.ts
  7. └── main.ts

通过本文的实践指导,开发者可以系统掌握NestJS中WebSocket通信的实现方法,从基础环境搭建到高级功能扩展形成完整知识体系。建议在实际项目中结合具体业务场景进行功能定制,并持续关注框架更新以引入新的优化特性。