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

如何在NestJS中间件中正确注入Service?解决依赖注入报错

在NestJS中间件中正确注入Service的解决方案

我有一个用于验证用户配额(quota)的中间件,需要注入操作数据库的Service来检查配额。

中间件代码

export class PointMaxStorageMiddleware implements NestMiddleware {

    constructor(private readonly points: PointsService) {}

    async use(req: Request, res: Response, next: NextFunction) {
        const total = await this.points.count('user-id-test');
        if (total >= LIMIT) throw new HttpException('error sample', 400);
        // ...
    }
}

Service类代码

@Injectable()
export class PointsService {
    private readonly logger = new Logger(PointsService.name);

    constructor(
        @InjectModel(Point.name)
        private readonly collection: Model<PointDocument>,
    ) {}

    async count(userId: string): Promise<number> {
        return await this.collection.countDocuments({ userId: userId });
    }
}

我的Service类已添加Injectable装饰器,且在项目其他模块中可正常使用,但将其注入中间件时,出现错误:

Cannot read properties of undefined (reading 'count')

注:count方法确实存在于该Service中。

我还尝试了以下写法:

constructor(
    @Inject(PointsService) private readonly points: PointsService,
) {}

此时出现错误:

Nest can't resolve dependencies of the PointsService (?). Please make sure that the argument PointModel at index [0] is available in the AppModule context.
Potential solutions:

  • If PointModel is a provider, is it part of the current AppModule?
  • If PointModel is exported from a separate @Module, is that module imported within AppModule? @Module({ imports: [ /* the Module containing PointModel */ ]})
    Error: Nest can't resolve dependencies of the PointsService (?). Please make sure that the argument PointModel at index [0] is available in the AppModule context.

我也尝试在AppModule中添加自定义Provider:

providers: [
    {
        provide: 'POINT_SERVICE',
        useClass: PointsService,
    },
]

并修改构造函数:

constructor(
    @Inject('POINT_SERVICE') private readonly points: PointsService,
) {}

但仍出现上述相同的依赖解析错误。请问如何在NestJS中间件中正确注入Service?


解决步骤

1. 确保依赖模块正确导入与导出

PointsService依赖PointModel(来自Mongoose),所以必须保证中间件所在模块(如AppModule)已导入包含PointModel的业务模块(比如PointsModule),且该业务模块已导出PointsService:

// PointsModule.ts
@Module({
  imports: [MongooseModule.forFeature([{ name: Point.name, schema: PointSchema }])],
  providers: [PointsService],
  exports: [PointsService] // 导出Service,允许其他模块注入
})
export class PointsModule {}

在AppModule中导入该模块:

// AppModule.ts
@Module({
  imports: [PointsModule],
  // 其他配置
})
export class AppModule {}

2. 正确注册中间件

NestJS中间件有两种注册方式,需对应正确的注入逻辑:

方式一:模块内注册(推荐)

通过模块的configure方法注册中间件,Nest会自动处理依赖注入,中间件构造函数无需额外装饰器:

// AppModule.ts
@Module({
  imports: [PointsModule],
})
export class AppModule implements NestModule {
  configure(consumer: MiddlewareConsumer) {
    consumer
      .apply(PointMaxStorageMiddleware)
      .forRoutes('your-target-route'); // 指定中间件生效的路由
  }
}

中间件构造函数保持原有写法即可:

constructor(private readonly points: PointsService) {}

方式二:全局注册

若需全局生效,需手动从应用容器中获取Service实例并传入中间件:

// main.ts
async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  const pointsService = app.get(PointsService);
  app.use(new PointMaxStorageMiddleware(pointsService));
  await app.listen(3000);
}
bootstrap();

3. 避免重复声明Provider

不要在AppModule的providers中重复添加PointsService或自定义POINT_SERVICE,因为PointsService已在PointsModule中声明并导出,重复声明会导致Nest创建多个实例,引发依赖解析冲突。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 18:10:27