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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 04:50:57