NestJS模块循环依赖:拦截器注入LogsService启动报错
NestJS拦截器依赖注入问题解决方案
问题分析
- 给拦截器加
@Injectable()时,启动报错:Nest can't resolve dependencies of the LogsInterceptor (?),本质是依赖未在模块中正确注册,Nest找不到要注入的LogsService。 - 移除
@Injectable()时,应用能启动但调用服务方法报错:TypeError: Cannot read properties of undefined (reading 'logRequestService'),因为Nest不会对无装饰器的类做依赖注入,this.logService始终是undefined。
分步解决
1. 保留拦截器的@Injectable()装饰器
依赖注入的前提是类必须被@Injectable()标记,修改拦截器代码:
import { CallHandler, ExecutionContext, Injectable, NestInterceptor } from '@nestjs/common'; import { Observable, tap } from 'rxjs'; import { LogsService } from './logs-service'; import { ILogModel } from './ILogModel'; @Injectable() // 必须保留这个装饰器 export class LogsInterceptor implements NestInterceptor { constructor(private logService: LogsService) {} // 其余代码不变 }
2. 在模块中注册所有依赖
确保LogsService、LogsInterceptor和DBConnection都被添加到模块的providers数组中。
如果用独立的LogsModule:
import { Module } from '@nestjs/common'; import { LogsService } from './logs-service'; import { LogsInterceptor } from './logs-interceptor'; import { DBConnection } from '../database/database.service'; @Module({ providers: [LogsService, LogsInterceptor, DBConnection], exports: [LogsInterceptor] // 其他模块要使用拦截器时需导出 }) export class LogsModule {}
如果直接在AppModule中注册:
import { Module } from '@nestjs/common'; import { LogsService } from './logs/logs-service'; import { LogsInterceptor } from './logs/logs-interceptor'; import { DBConnection } from './database/database.service'; @Module({ providers: [LogsService, LogsInterceptor, DBConnection], }) export class AppModule {}
3. 修复this指向问题
tap操作符的回调用普通函数会导致this指向丢失,调用this.logRequest时,方法内的this不再指向拦截器实例,进而this.logService为undefined。
把回调改成箭头函数:
return next.handle().pipe( tap({ next: (response) => { // 箭头函数保留this指向 log = { ip: args[0].hostname, username: args[0].user.nombre_completo, tipo: args[0].method, path: args[0].originalUrl, query: args[0].query, params: args[0].params, body: args[0].body, response, statuscode: responseStatus.statusCode, }; this.logRequest(log); console.log('after'); return response; }, error: (error) => { // 箭头函数保留this指向 console.log(error); log = { ip: args[0].hostname, username: args[0].user.nombre_completo, tipo: args[0].method, path: args[0].originalUrl, query: args[0].query, params: args[0].params, body: args[0].body, response: error, statuscode: error.status, }; this.logRequest(log); console.log(log); console.log('entrado por error'); return error; }, }), );
或者在构造函数中绑定this:
constructor(private logService: LogsService) { this.logRequest = this.logRequest.bind(this); }
验证
- 确认所有依赖都在模块
providers中注册 - 拦截器保留
@Injectable()装饰器 - 修复
this指向后重启应用,测试请求日志是否正常写入
内容的提问来源于stack exchange,提问作者tsiPlus
相关产品推荐
相关产品推荐

