NestJS Socket.io 重复WebSocket请求问题排查求助
问题分析与解决方案
根本原因
- 重复的连接事件监听:你在
onModuleInit中手动绑定了Socket.io的connection事件,而NestJS的WebSocketGateway本身会通过内部机制处理连接,这种手动绑定可能导致连接逻辑被执行多次,进而引发后续消息处理的重复触发。 - Gateway实例重复注册:如果
ChatGateway在多个模块的providers数组中被重复声明,会导致多个Gateway实例同时运行,每个实例都会监听newChatMessage事件,最终造成服务端收到重复请求。
修复步骤
1. 使用NestJS标准的连接处理钩子替换手动监听
NestJS提供了OnGatewayConnection生命周期接口,专门用于处理WebSocket连接事件,这是官方推荐的规范做法,避免和内部逻辑冲突。
修改Gateway代码:
import { ConnectedSocket, MessageBody, SubscribeMessage, WebSocketGateway, WebSocketServer, OnGatewayConnection, } from '@nestjs/websockets'; import { Server, Socket } from 'socket.io'; import { OnModuleInit } from '@nestjs/common'; import { CreativeService } from '../modules/creative/creative.service'; import { CreateMessageDto } from './dto/chat.dto'; import { JwtService } from '@nestjs/jwt'; import { UsersService } from '../modules/users/users.service'; @WebSocketGateway({ cors: { origin: '*', }, }) export class ChatGateway implements OnModuleInit, OnGatewayConnection { constructor( private readonly creativeService: CreativeService, private readonly jwtService: JwtService, private readonly userService: UsersService, ) {} @WebSocketServer() server: Server; onModuleInit(): any { // 移除手动绑定的connection事件监听 } // 替换为标准的连接处理方法 async handleConnection(socket: Socket) { console.log('socket', socket.id); try { const token = socket.handshake.headers.authorization; // 增加token存在性校验,避免无token时报错 if (!token) { throw new Error('Authorization token is required'); } const splitToken = token.split(' ')[1]; const decodedToken = this.jwtService.verify(splitToken); const requestUser = await this.userService.findOne(decodedToken.id); console.log('I am getting Called from handleConnection'); if (!requestUser) { throw new Error('User not found'); } socket['user'] = requestUser; } catch (error) { socket.emit('error', { message: error.message }); socket.disconnect(); } } @SubscribeMessage('newChatMessage') onNewMessage( @MessageBody() body: CreateMessageDto, @ConnectedSocket() socket: Socket, ) { const user = socket['user']; if (!user) { throw new Error('User not found'); } console.log('Received message', body, 'From', user.email); console.log('I am getting Called from SubscribeMessage'); this.server.emit('newChatMessage', { videoId: body.videoId, sender: user.email, message: body.message, }); } }
2. 检查Gateway的模块注册情况
确保ChatGateway只在一个模块的providers数组中声明,比如只在AppModule或者对应的功能模块中注册,避免重复实例化:
// 示例:在AppModule中注册Gateway @Module({ providers: [ChatGateway], // 仅在此处声明一次 // ...其他模块配置 }) export class AppModule {}
3. 验证客户端连接(可选)
如果上述修复后问题仍存在,可以检查客户端是否意外创建了多个Socket实例。但你提到Postman也出现相同问题,所以服务端的问题概率更高,优先排查前两步。
内容的提问来源于stack exchange,提问作者subhos
相关产品推荐
相关产品推荐

