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

NestJS+WebSocket开发多人卡牌游戏遇this.server.of()不是函数报错

问题分析与解决

核心问题

你遇到的报错源于对NestJS WebSocket中server实例的误用:

  • this.server.of is not a function:当前获取的server是socket.io的单个命名空间实例,而非主Server实例,而Namespace没有of方法。
  • this.server.to报错:调用to时目标房间无效,或server实例不符合预期,导致内部遍历children时读取到undefined。

解决方案

1. 注入正确的socket.io主Server实例

在游戏网关中,通过@WebSocketServer()获取socket.io的主Server实例(而非单个命名空间),再通过of方法定位到目标游戏命名空间:

import { WebSocketGateway, WebSocketServer } from '@nestjs/websockets';
import { Server } from 'socket.io';

@WebSocketGateway({
  namespace: /^\/game\/[a-zA-Z0-9]+$/, // 匹配带斜杠的动态游戏路径
})
export class GameGateway {
  @WebSocketServer()
  private readonly io: Server; // 注入socket.io主Server实例

  // 处理游戏注册关闭事件
  handleGameRegistrationClosed(game: any) {
    // 获取对应游戏的命名空间并广播
    const gameNamespace = this.io.of(`/game/${game._id}`);
    gameNamespace.emit('pregame', game);
  }
}

2. 修正动态命名空间匹配规则

确保正则表达式与客户端连接路径一致,客户端连接的是/game/xxx,正则需包含开头的斜杠,避免命名空间匹配失败。

3. 可选:连接时维护命名空间引用

如果需要更精准的状态管理,可在玩家连接时保存对应命名空间的引用,后续直接调用:

private gameNamespaces = new Map<string, any>();

handleConnection(client: any) {
  // 从连接路径提取游戏ID
  const gameId = client.nsp.name.split('/').pop();
  if (gameId) {
    this.gameNamespaces.set(gameId, client.nsp);
  }
}

handleGameRegistrationClosed(game: any) {
  const gameNamespace = this.gameNamespaces.get(game._id);
  if (gameNamespace) {
    gameNamespace.emit('pregame', game);
  }
}

额外注意事项

  • 卡牌隐私控制:广播game对象前,需过滤敏感数据,比如给每个玩家单独发送个性化的卡牌信息(用client.emit替代全局广播),避免泄露他人卡牌。
  • 内存泄漏防范:游戏结束后及时清理对应命名空间的状态和引用,释放内存。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 14:22:41