如何在NestJS的Services中获取中间件挂载的req.user对象
方案1:使用请求作用域注入Request对象
NestJS内置了REQUEST注入令牌,配合请求作用域可以直接在Service中注入当前请求对象,无需从Controller层传递:
- 首先给你的Service设置请求作用域,注入
REQUEST令牌:
import { Injectable, Scope, Inject } from '@nestjs/common'; import { REQUEST } from '@nestjs/core'; import { Request } from 'express'; @Injectable({ scope: Scope.REQUEST }) export class YourBusinessService { constructor(@Inject(REQUEST) private req: Request) {} someBusinessMethod() { // 直接获取用户ID const userId = this.req.user.id; // 后续业务逻辑 } }
- 注意事项:请求作用域的Provider会随每次请求创建、销毁,不能直接注入到单例Provider中,否则会导致父Provider也被降级为请求作用域,高并发场景下会有一定性能损耗。
方案2:使用AsyncLocalStorage存储请求上下文
该方案不会修改Service的单例属性,无作用域污染问题,性能更优,是更推荐的生产级方案:
- 先创建全局共享的AsyncLocalStorage实例
// src/common/async-local-storage.ts import { AsyncLocalStorage } from 'async_hooks'; // 泛型可根据你的User类型自定义 export const als = new AsyncLocalStorage<{ user: any }>();
- 修改你的身份认证中间件,在请求链路中注入上下文
import { als } from 'src/common/async-local-storage'; @Injectable() export class AuthenticationMiddleware implements NestMiddleware { async use(req: any, res: any, next: () => void) { const authHeaders = req.headers.authorization; if (authHeaders) { // 原有校验逻辑,获取user对象 req.user = user; // 将用户信息存入AsyncLocalStorage,再执行后续请求链路 als.run({ user }, next); } else { throw new UnauthorizedException(); } } }
- 任意Service中直接读取当前用户信息
import { als } from 'src/common/async-local-storage'; import { UnauthorizedException } from '@nestjs/common'; @Injectable() export class YourBusinessService { someBusinessMethod() { const store = als.getStore(); if (!store?.user) { throw new UnauthorizedException('用户身份未校验'); } const userId = store.user.id; // 后续业务逻辑 } }
- 注意事项:正常HTTP请求链路的异步操作都能正确继承上下文,如果你手动创建了脱离请求链路的异步任务(如未绑定上下文的setTimeout、独立队列任务),需要单独处理上下文传递。
内容的提问来源于stack exchange,提问作者markWanka
相关产品推荐
相关产品推荐

