You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

NestJS中Socket.io客户端连接后立即断开及@SubscribeMessage事件监听失效问题

问题排查与解决方法

我帮你梳理出几个核心问题,咱们一个个解决:

1. 生命周期钩子误用了@SubscribeMessage装饰器

你现在把handleConnectionhandleDisconnect这两个NestJS WebSocket生命周期方法绑定到了自定义事件上(is-onlineis-offline),这完全搞错了逻辑:

  • handleConnection是当客户端成功连接时自动触发的生命周期钩子,不需要加@SubscribeMessage
  • handleDisconnect是当客户端断开连接时自动触发的钩子,同样不需要装饰器
    这种错误会导致NestJS无法正确处理连接生命周期,直接引发客户端连接后立即断开的问题。

2. 缺少CORS跨域配置

前端和NestJS服务端通常运行在不同端口,默认情况下WebSocket网关会拒绝跨域连接,这也是连接后立刻断开的常见原因。

3. 可选:Socket.io版本兼容性

如果前端socket.io-client和服务端socket.io版本不匹配,也会出现连接异常,要确保两端版本一致(比如都用4.x系列)。


修正后的服务端代码

import { Server, Socket } from 'socket.io';
import { Injectable, WebSocketGateway, OnGatewayConnection, OnGatewayDisconnect, OnGatewayInit } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { User } from '../entities/user.entity';
import { Repository } from 'typeorm';
import { Messenger } from './entities/messenger.entity';

@Injectable()
@WebSocketGateway(5000, {
  // 配置CORS,替换成你的前端实际地址
  cors: {
    origin: "http://localhost:3000",
    credentials: true,
  },
})
export class MessengerGateway implements OnGatewayConnection, OnGatewayDisconnect, OnGatewayInit {
  constructor(
    @InjectRepository(User) private userRepository: Repository<User>,
    @InjectRepository(Messenger) private messageRepository: Repository<Messenger>,
  ) {}

  @SubscribeMessage('loadPeople')
  handleLoadPeople(client: Socket, data: { token: string }) {
    console.log('Received loadPeople data:', data); // 现在应该能正常打印了
    // 这里可以添加后续业务逻辑,比如验证token、查询在线用户等
  }

  async afterInit(server: Server) {
    console.log('WebSocket Gateway initialized successfully');
  }

  // 去掉@SubscribeMessage,恢复生命周期钩子的默认行为
  async handleConnection(client: Socket) {
    console.log(`Client connected: ${client.id}`);
  }

  // 同样去掉@SubscribeMessage
  async handleDisconnect(client: Socket) {
    console.log(`Client disconnected: ${client.id}`);
  }
}

优化后的前端代码

import { io } from "socket.io-client";
const ENDPOINT = "http://localhost:5000"; // 加上http前缀,避免协议解析问题
let socket;

function App(){
  useEffect(()=>{
    socket = io(ENDPOINT, {
      withCredentials: true, // 和后端CORS配置对应
    });
    
    // 等连接成功后再发送事件,避免提前发送导致丢失
    socket.on('connect', () => {
      console.log('Successfully connected to WebSocket server');
      socket.emit('loadPeople', {token: localStorage.token});
    });

    // 监听连接错误,方便排查问题
    socket.on('connect_error', (err) => {
      console.error('WebSocket connection error:', err);
    });

    // 组件卸载时主动断开连接,避免内存泄漏
    return () => {
      if (socket) socket.disconnect();
    };
  },[])
  return (
    // 你的组件内容
  )
}

验证步骤

  1. 检查版本一致性:
    • 服务端安装:npm install socket.io@4.x
    • 前端安装:npm install socket.io-client@4.x
  2. 启动NestJS服务和前端项目
  3. 查看控制台:
    • 服务端会打印网关初始化、客户端连接日志
    • 前端会打印连接成功日志
    • 服务端会正常输出loadPeople事件接收的数据

内容的提问来源于stack exchange,提问作者Vahan

火山引擎 最新活动