You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

NestJS Socket.io 重复WebSocket请求问题排查求助

问题分析与解决方案

根本原因

  1. 重复的连接事件监听:你在onModuleInit中手动绑定了Socket.io的connection事件,而NestJS的WebSocketGateway本身会通过内部机制处理连接,这种手动绑定可能导致连接逻辑被执行多次,进而引发后续消息处理的重复触发。
  2. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 09:42:43