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

NestJS:如何在REQUEST作用域提供者初始化前修改请求?

解决NestJS REQUEST作用域提供者初始化前修改请求的问题

针对你遇到的REQUEST作用域提供者无法获取Guard处理后用户信息的问题,有几个可行的方案:

方案一:用Node.js AsyncLocalStorage存储用户信息

这个方案绕开直接依赖请求对象的限制,在请求最早期的中间件中存储认证信息,供后续提供者读取:

  • 首先创建一个单例的AsyncLocalStorage实例作为提供者:
    import { AsyncLocalStorage } from 'async_hooks';
    import { Injectable } from '@nestjs/common';
    
    @Injectable()
    export class RequestContext {
      private readonly als = new AsyncLocalStorage<Map<string, any>>();
    
      startContext() {
        return this.als.run(new Map(), () => {});
      }
    
      set(key: string, value: any) {
        const store = this.als.getStore();
        if (store) store.set(key, value);
      }
    
      get<T>(key: string): T | undefined {
        const store = this.als.getStore();
        return store?.get(key) as T;
      }
    }
    
  • 编写全局中间件,在其中完成Passport认证并将用户存入AsyncLocalStorage:
    import { Injectable, NestMiddleware } from '@nestjs/common';
    import { Request, Response, NextFunction } from 'express';
    import { RequestContext } from './request-context.service';
    import passport from 'passport';
    
    @Injectable()
    export class AuthMiddleware implements NestMiddleware {
      constructor(private readonly requestContext: RequestContext) {}
    
      async use(req: Request, res: Response, next: NextFunction) {
        // 启动ALS上下文
        this.requestContext.startContext();
        // 执行Passport认证逻辑
        await new Promise((resolve, reject) => {
          passport.authenticate('jwt', { session: false }, (err, user) => {
            if (err) return reject(err);
            if (user) this.requestContext.set('user', user);
            resolve(null);
          })(req, res, resolve);
        });
        next();
      }
    }
    
  • 在REQUEST作用域提供者的useFactory中,通过AsyncLocalStorage获取用户:
    {
      provide: 'DYNAMIC_SERVICE',
      useFactory: async (requestContext: RequestContext) => {
        const user = requestContext.get('user');
        // 用user配置动态实例
        return new DynamicService(user);
      },
      inject: [RequestContext],
      scope: Scope.REQUEST,
    }
    

方案二:直接使用Passport全局中间件

跳过NestJS的Guard层,在应用启动时直接挂载Passport的认证中间件,这个中间件的执行时机早于所有NestJS内置的请求处理逻辑,包括REQUEST作用域提供者的初始化:

// 在main.ts中
async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  // 直接挂载Passport认证中间件
  app.use(passport.authenticate('jwt', { session: false }));
  await app.listen(3000);
}
bootstrap();

这样请求进来后会先完成认证,用户信息被挂载到req.user,之后REQUEST作用域提供者的useFactory中就能直接从req对象读取到用户信息。

方案三:调整依赖注入顺序(不推荐)

如果你的REQUEST作用域提供者是被注入到控制器或其他晚于Guard执行的组件中,可以尝试将提供者的依赖改为REQUEST作用域的守卫实例,但这种方式依赖NestJS的注入顺序,稳定性较差,不推荐在生产环境使用。

内容的提问来源于stack exchange,提问作者Gdfelt

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 08:17:23