NestJS中为Colyseus非实例化类注入服务的方案咨询
在NestJS中为Colyseus房间类实现依赖注入的解决方案
问题背景
在NestJS项目中集成Colyseus时,Colyseus框架会自行实例化房间类(如GameRoom),而非由NestJS的DI容器创建,导致房间类中通过构造函数注入的服务(如AuthService)在回调方法(如onAuth)中为undefined。以下提供两种可行的注入方案:
方案1:通过Colyseus房间选项传递服务实例
这是最直接的方案,利用Colyseus的房间定义选项,将Nest管理的服务实例传递给房间类:
在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); } }修改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能力:
创建全局容器持有者
// 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; } }在根模块注册并导出全局服务
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 {}修改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
相关产品推荐
相关产品推荐

