NestJS中使用@UseGuards时循环依赖引发未定义依赖问题
问题排查:NestJS 中
TypeError: Cannot read property 'getUser' of undefined 错误 现有代码实现
JwtAuthGuard
import { AuthGuard } from '@nestjs/passport'; export class JwtAuthGuard extends AuthGuard('jwt') {}
ApiKeyGuard
@Injectable() export class ApiKeyGuard implements CanActivate { constructor(private configService: ConfigService) {} canActivate (context: ExecutionContext) { const request = context.switchToHttp().getRequest(); const { apikey } = request.headers; if (apikey === env.get('API_KEY')) return true; else throw new UnauthorizedException(); } }
UserController
@Get('/:users') @UseGuards(ApiKeyGuard) getUser(): { return this.userService.getUser(); }
UserService
@Injectable() export class UserService { constructor(private dummyService:DummyService) {} getUser() { return this.dummyService.getUser(); } }
CouponModule
@Module({ imports: [...], controllers: [userController], providers: [....], exports: [UserService], }) export class CouponModule {}
额外背景
- 存在
CouponModule模块,其CouponController同样使用@UseGuards() CouponService与UserService存在循环依赖,两者均依赖DummyService
问题现象
所有使用 @UseGuards(ApiKeyGuard) 的 API 处理请求时均报错:
TypeError: Cannot read property 'getUser' of undefined
- 使用
@UseGuards(JwtAuthGuard)时应用运行正常 - 即使移除
@UseGuards()装饰器,错误仍存在 - 已尝试将
DummyService添加到两个模块的providers中,问题未解决
排查与解决方案
1. 定位错误根源
错误提示的 getUser 未定义,说明调用该方法时所属对象为 undefined。结合代码,可能的触发点有两个:
UserService中this.dummyService.getUser()→dummyService未正确注入- 控制器中
this.userService.getUser()→userService未正确注入
2. 修复循环依赖处理
CouponService 和 UserService 的循环依赖是核心诱因之一,NestJS 对循环依赖需要显式处理:
- 在服务注入时使用
forwardRef():// UserService.ts import { forwardRef, Inject } from '@nestjs/common'; import { CouponService } from './coupon.service'; @Injectable() export class UserService { constructor( private dummyService: DummyService, @Inject(forwardRef(() => CouponService)) private couponService: CouponService ) {} }// CouponService.ts import { forwardRef, Inject } from '@nestjs/common'; import { UserService } from './user.service'; @Injectable() export class CouponService { constructor( private dummyService: DummyService, @Inject(forwardRef(() => UserService)) private userService: UserService ) {} } - 模块注册时配合
forwardRef(若跨模块循环依赖):// CouponModule.ts import { forwardRef } from '@nestjs/common'; import { OtherModule } from '../other/other.module'; @Module({ imports: [forwardRef(() => OtherModule)], providers: [UserService, CouponService, DummyService], controllers: [UserController, CouponController], exports: [UserService], }) export class CouponModule {}
3. 修正 ApiKeyGuard 的配置读取错误
ApiKeyGuard 中注入了 configService,但使用了未定义的 env 对象,修正为:
@Injectable() export class ApiKeyGuard implements CanActivate { constructor(private configService: ConfigService) {} canActivate (context: ExecutionContext) { const request = context.switchToHttp().getRequest(); const { apikey } = request.headers; if (apikey === this.configService.get('API_KEY')) return true; else throw new UnauthorizedException(); } }
虽然这不是直接导致 getUser 错误的原因,但可能引发异常中断流程。
4. 确保依赖注入的完整性
- 控制器必须正确注入
UserService:@Controller('users') export class UserController { constructor(private readonly userService: UserService) {} @Get('/:users') @UseGuards(ApiKeyGuard) getUser() { return this.userService.getUser(); } } - 若
DummyService为多模块共用,可注册为全局模块避免重复配置:
其他模块只需导入@Global() @Module({ providers: [DummyService], exports: [DummyService], }) export class DummyModule {}DummyModule即可使用DummyService,无需重复添加到providers。
内容的提问来源于stack exchange,提问作者Huy Jayden Nguyen
相关产品推荐
相关产品推荐

