如何在可注入构造函数中添加参数但仍然让 Nest 管理依赖注入?

How can I add an argument in an injectable constructor but still let Nest manage dependency injection?

我创建了一个自定义守卫,如下所示:

@Injectable()
export class MyCustomGuard implements CanActivate {
  constructor(
    private reflector: Reflector,
    private myService: MyService,
  ) {}

  async canActivate(context: ExecutionContext): Promise<boolean> {
    const request = context.switchToHttp().getRequest();
    const idParam = request.params.id;
    ...
  }
}

我在我的控制器中这样使用它:

@UseGuards(MyCustomGuard)
@Controller('my-controller')
export class MyController {
 ...
}

它工作正常,但我想在实例化守卫时将 id 参数键设置为参数,如下所示:

@Injectable()
export class MyCustomGuard implements CanActivate {
  constructor(
    private idKey: string,
    private reflector: Reflector,
    private myService: MyService,
  ) {}

  async canActivate(context: ExecutionContext): Promise<boolean> {
    const request = context.switchToHttp().getRequest();
    const idParam = request.params[idKey];
    ...
  }
}

然后我将不得不在我的控制器中手动实例化守卫:

@UseGuards(new MyCustomGuard('id', ...?))
@Controller('my-controller')
export class MyController {
  ...
}

我的问题是,如果我这样做,那么我将不得不手动实例化我的守卫的其他构造函数参数:反射器和服务。这是可能的,但出于简单性和性能原因,我宁愿让 Nest 管理它。那么我的问题是:有没有办法手动实例化守卫(这样我就可以给它 idKey 参数)但仍然让 Nest 管理其他参数的依赖注入? 在这里使用 ModuleRef 似乎可行,但我真的不知道这样做是否正确。

与其将 idKey 作为构造函数参数传递,我建议将其反映为 class 的元数据。这样,你可以做类似

的事情
@IdKey('id')
@UseGuards(MyCustomGuard)
@Controller('my-controller')
export class MyController {
...
}

在你的守卫中你会做类似的事情

@Injectable()
export class MyCustomGuard implements CanActivate {
  constructor(
    private reflector: Reflector,
    private myService: MyService,
  ) {}

  async canActivate(context: ExecutionContext): Promise<boolean> {
    const request = context.switchToHttp().getRequest();
    const idParam = request.params.id;
    const idKey = this.getIdKey(context);
    ...
  }

  getIdKey(context: ExecutionContext) {
    return this.reflector.get('id-key', context.getClass());
  }
}

这是假设您的 @IdKey() 看起来像

export const IdKey = (key: string) => SetMetadata(key);

其中 SetMetadata 来自 @nestjs/common

You can read more about @SetMetadata() and metadata rerflection here