NestJS请求作用域服务导致无关服务上下文丢失问题排查
请求作用域类在Nest中的行为与moduleRef获取实例的差异分析
一、Nest请求作用域的核心逻辑
Nest的作用域直接决定类实例的生命周期:
scope.DEFAULT:默认单例模式,整个应用生命周期内仅存在一个实例scope.REQUEST:每个请求都会生成全新实例,实例与当前请求的上下文绑定;所有依赖请求作用域类的类,会被自动提升为请求作用域(即使原本是单例)- 请求作用域实例的上下文包含当前请求的所有关联数据(如你提到的SessionService会话信息),只有同属一个请求上下文的实例才能共享这些数据
二、构造注入与moduleRef.get的关键差异
1. 构造注入的行为
当ServiceA通过构造函数注入ServiceB时,Nest在处理请求的初始阶段会递归构建整个依赖链的实例:
- 由于ServiceB依赖REQUEST作用域的LocalStorageService,ServiceB会被自动提升为REQUEST作用域
- 所有实例(包括被提升的ServiceA或本身为请求作用域的ServiceA)都会绑定到当前请求的上下文,自然能共享SessionService的会话数据
2. moduleRef.get的行为
你使用moduleRef.get(ServiceB, {strict: false})获取实例时,存在核心问题:
- 对于REQUEST作用域的类,
moduleRef.get如果不指定当前请求的上下文,Nest会创建一个脱离当前请求上下文的新实例 - 这个新实例属于独立的请求上下文,无法访问当前请求中SessionService存储的会话数据,因此你会看到ServiceB中没有会话信息
- 当LocalStorageService是单例时,ServiceB也会保持单例状态,
moduleRef.get获取的是全局唯一实例,能访问单例SessionService中的数据(但会导致跨请求上下文污染,这也是你必须使用请求作用域的原因)
三、你的场景问题根源
当LocalStorageService设为REQUEST作用域后:
- ServiceB被自动提升为REQUEST作用域
- ServiceA如果是单例(默认),用
moduleRef.get获取ServiceB时未传入当前请求的上下文参数,导致创建了新的、独立的ServiceB实例,该实例的上下文与当前请求完全隔离,因此无法获取SessionService的会话数据 - 改用构造注入后,Nest会在当前请求的上下文内构建ServiceB实例,与SessionService共享同一上下文,因此能正常访问会话数据
内容的提问来源于stack exchange,提问作者user1728296
相关产品推荐
相关产品推荐

