NestJS:如何在中间件中获取 ExecutionContext

jue*_*hus 5 javascript node.js nestjs

我们将 NestJS 用于我们的 NodeJS 应用程序。在我们的应用程序中,我们有一些中间件/守卫/拦截器来创建用户请求上下文、验证 jwt 令牌、拦截请求/响应等。

我们还实现了一些自定义装饰器,为我们的端点设置元数据。在守卫/拦截器中使用这些数据非常容易,因为你在 canActivate/intercept 函数中有 ExecutionContext。

但是我们在中间件中深深地缺少这个功能。 有没有机会在 NestJS 中间件中获取/注入 ExecutionContext?

例如

export class SomeMiddleware implements NestMiddleware {
    constructor(@Inject('ExecutionContext') context: ExecutionContext) {}

    use(req, res, next) {
        // get data from context / decorator
        Reflect.getMetadata(SOME_KEY, context.getHandler());

        next();
    }
}
Run Code Online (Sandbox Code Playgroud)

Maj*_*uti -1

您可以使用cls-hooked或其他类似的模块来创建自定义上下文。为此,您可以拥有一个上下文创建者中间件,例如:

import { Injectable, NestMiddleware } from '@nestjs/common';
import { Request, Response, NextFunction } from 'express';
import cls from 'cls-hooked';

@Injectable()
export class ContextCreatorMiddleware implements NestMiddleware {
  private readonly contextNamespace: cls.Namespace<Record<string, any>>;

  constructor() {
    this.contextNamespace =
      cls.getNamespace('context-name') ||
      cls.createNamespace('context-name');
  }

  use(req: Request, res: Response, next: NextFunction) {
    this.requestTracingNamespace.bindEmitter(req);
    this.requestTracingNamespace.bindEmitter(res);

    return new Promise((resolve) => {
      this.contextNamespace.run(async () => {
        this.contextNamespace.set('YOUR_KEY', YOUR_VALUE);
        resolve(next());
      });
    });
  }
}
Run Code Online (Sandbox Code Playgroud)

然后您可以在其他服务中使用您的上下文,例如:

import { Injectable } from '@nestjs/common';
import cls from 'cls-hooked';

@Injectable()
export class YourService {
  public constructor() {}

  public f1() {
    const contextNamespace = cls.getNamespace('context-name');
    const yourValue = contextNamespace?.get('YOUR_KEY');
  }
}
Run Code Online (Sandbox Code Playgroud)

请记住在您的 AppModule 中应用中间件:

export class AppModule {
  configure(consumer: MiddlewareConsumer) {
    consumer.apply(ContextCreatorMiddleware).forRoutes('*');
  }
}
Run Code Online (Sandbox Code Playgroud)