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

NestJS中为Colyseus非实例化类注入服务的方案咨询

在NestJS中为Colyseus房间类实现依赖注入的解决方案

问题背景

在NestJS项目中集成Colyseus时,Colyseus框架会自行实例化房间类(如GameRoom),而非由NestJS的DI容器创建,导致房间类中通过构造函数注入的服务(如AuthService)在回调方法(如onAuth)中为undefined。以下提供两种可行的注入方案:


方案1:通过Colyseus房间选项传递服务实例

这是最直接的方案,利用Colyseus的房间定义选项,将Nest管理的服务实例传递给房间类:

  1. 在Colyseus服务类中注入目标服务

    import { Injectable, OnModuleInit } from '@nestjs/common';
    import { Server } from 'colyseus';
    import { AuthService } from './auth/auth.service';
    import { GameRoom } from './game-room';
    
    @Injectable()
    export class ColyseusBootstrap implements OnModuleInit {
      private colyseusServer: Server;
    
      constructor(private readonly authService: AuthService) {}
    
      async onModuleInit() {
        this.colyseusServer = new Server({ /* 你的Colyseus配置 */ });
        // 定义房间时将AuthService通过选项传递
        this.colyseusServer.define("GameRoom", GameRoom, {
          authService: this.authService
        });
        await this.colyseusServer.listen(2567);
      }
    }
    
  2. 修改GameRoom类接收服务实例

    import { Room, Client, ServerError } from 'colyseus';
    import { GameRoomState } from './game-room.state';
    import { AuthService } from '../auth/auth.service';
    
    export class GameRoom extends Room<GameRoomState> {
      private authService: AuthService;
    
      onCreate(options: { authService: AuthService }) {
        this.setState(new GameRoomState());
        // 从选项中获取AuthService实例
        this.authService = options.authService;
      }
    
      async onAuth(client: Client, options: any, request: IncomingMessage) {
        if (!this.authService) {
          throw new ServerError(500, 'Auth service not initialized');
        }
    
        if (request.headers.cookie) {
          const sessionId = this.authService.getSessionId(request.headers.cookie);
          const user = await this.authService.authSessionId(sessionId);
    
          if (!user) {
            throw new ServerError(401, 'Invalid Session ID');
          }
          return true;
        } else {
          throw new ServerError(401, 'You need to provide a "session" cookie with a valid Session ID');
        }
      }
    }
    

方案2:利用Nest全局ModuleRef获取服务

适合需要注入多个服务的场景,通过全局容器复用Nest的DI能力:

  1. 创建全局容器持有者

    // src/utils/nest-container.ts
    import { Injectable } from '@nestjs/common';
    import { ModuleRef } from '@nestjs/core';
    
    @Injectable()
    export class NestContainer {
      static moduleRef: ModuleRef;
    
      constructor(moduleRef: ModuleRef) {
        NestContainer.moduleRef = moduleRef;
      }
    }
    
  2. 在根模块注册并导出全局服务

    import { Module, Global } from '@nestjs/common';
    import { AuthService } from './auth/auth.service';
    import { NestContainer } from './utils/nest-container';
    
    @Global()
    @Module({
      providers: [AuthService, NestContainer],
      exports: [AuthService],
    })
    export class AppModule {}
    
  3. 修改GameRoom类从全局容器获取服务

    import { Room, Client, ServerError } from 'colyseus';
    import { GameRoomState } from './game-room.state';
    import { AuthService } from '../auth/auth.service';
    import { NestContainer } from '../utils/nest-container';
    
    export class GameRoom extends Room<GameRoomState> {
      private authService: AuthService;
    
      onCreate(options: any) {
        this.setState(new GameRoomState());
        // 从全局ModuleRef中获取AuthService实例
        this.authService = NestContainer.moduleRef.get(AuthService);
      }
    
      async onAuth(client: Client, options: any, request: IncomingMessage) {
        if (!this.authService) {
          throw new ServerError(500, 'Auth service not initialized');
        }
    
        if (request.headers.cookie) {
          const sessionId = this.authService.getSessionId(request.headers.cookie);
          const user = await this.authService.authSessionId(sessionId);
    
          if (!user) {
            throw new ServerError(401, 'Invalid Session ID');
          }
          return true;
        } else {
          throw new ServerError(401, 'You need to provide a "session" cookie with a valid Session ID');
        }
      }
    }
    

注意事项

  • 两种方案都需要确保Colyseus服务器在Nest模块初始化完成后启动(使用OnModuleInit钩子),避免服务未初始化的问题。
  • 多进程部署场景下,方案1的选项传递更可靠;方案2需要确保每个进程都能正确获取ModuleRef。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 01:57:34