在NestJS中,如何在自定义方法装饰器中获取执行上下文或请求实例?

问题描述 投票:0回答:3

我有一个像这样的自定义方法装饰器。

export function CustomDecorator() {

    return applyDecorators(
        UseGuards(JwtAuthGuard)
    );
}

在自定义装饰器中,我想获取请求头但不知道如何获取请求实例?

decorator nestjs
3个回答
11
投票

您将无法在类或方法装饰器中获取

ExectuionContext
对象或
Request
对象,因为这些装饰器在导入时立即运行。相反,应该做的是制作一个确实具有可用的
SuperGuard
ExecutionContext
。这个
SuperGuard
应该通过
constructor
将所有其他守卫注入其中,并且根据标头,您应该调用/返回所调用守卫的结果。像这样的东西:

@Injectable()
export class SuperGuard implements CanActivate {
  constructor(
    private readonly jwtAuthGuard: JwtAuthGuard,
    private readonly googleAuthGuard: GoogleAuthGuard,
  ) {}

  canActivate(context: ExecutionContext) {
    const req = context.switchToHttp().getRequest();
    if (req.headers['whatever'] === 'google') {
      return this.googleAuthGuard.canActivate(context);
    } else {
      return this.jwtAuthGuard.canActivate(context);
    }
  }
}

0
投票

我设法使用装饰器工厂内的

Inject
访问装饰器内的执行上下文。 这是我的装饰器,它吞下方法产生的错误并在发生异常时返回预定义的值。

import { Injectable, Scope, Inject, ExecutionContext } from '@nestjs/common';
import { CONTEXT } from '@nestjs/graphql';

@Injectable({ scope: Scope.REQUEST })
export class ExceptionsHandler {
  public constructor(@Inject(CONTEXT) private readonly context: ExecutionContext) {}

  private integrationsRequestErrors: unknown[] = [];

  public handle(error: unknown): void {
    // ADD error to context if necessary
    this.integrationsRequestErrors.push(error);
  }
}

export const ErrorSwallower = (options: {
  serviceImplementation: string;
  defaultValue: unknown;
  errorMessage?: string;
}): MethodDecorator => {
  const { defaultValue, integration } = options;
  const Injector = Inject(ExceptionsHandler);
  return (target: object, _propertyKey: string, descriptor: PropertyDescriptor) => {
    Injector(target, 'exceptionsHandler');
    const originalMethod = descriptor.value;
    descriptor.value = function (...args: unknown[]) {
      const exceptionHandler = this.experiment as ExceptionsHandler;
      try {
        const result = originalMethod.apply(this, args);
        if (result && result instanceof Promise) {
          return result.catch((error: unknown) => {
            exceptionHandler.handle({ error, integration });
            return defaultValue;
          });
        }
        return result;
      } catch (error) {
        exceptionHandler.handle({ error, integration });
        return defaultValue;
      }
    };
  };
};

这是上面的代码的实际应用:

@Injectable()
export class ExampleService {
  @ErrorSwallower({ serviceImplementation: 'ExampleClass', defaultValue: [] })
  private async getSomeData(args: IGetSomeDataArgs): Promise<ISomeData[]> {
    throw new Error('Oops');
  }
}


0
投票

Я поступаю следующим образом:

  1. Получаю контекст в конструкторе резолвера (если декоратор используется в резолвере).
constructor(@Inject(CONTEXT) private readonly context: ExecutionContext) {}
  1. В декораторе метода читаю контекст запроса из контекста выполнения метода.
export function CustomDecorator() {
    return applyDecorators(
        UseGuards(JwtAuthGuard)
        const context = this.context;
    );
}
© www.soinside.com 2019 - 2024. All rights reserved.