ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

NestJS 如何告别手动传参?nestjs-cls 快速上手:10 分钟接入 AsyncLocalStorage 异步上下文

NestJS 如何告别手动传参?nestjs-cls 快速上手:10 分钟接入 AsyncLocalStorage 异步上下文 NestJS 如何告别手动传参nestjs-cls 快速上手10 分钟接入 AsyncLocalStorage 异步上下文【免费下载链接】nestjs-clsA continuation-local storage (async context) module compatible with NestJSs dependency injection.项目地址: https://gitcode.com/gh_mirrors/ne/nestjs-clsnestjs-cls是一个专为 NestJS 打造的异步本地存储CLS / Async Context模块基于 Node.js 原生AsyncLocalStorage实现并与 NestJS 依赖注入无缝兼容。它让请求上下文数据用户信息、请求 ID、多租户连接等在整个请求生命周期内自动传递从此告别层层手动传参。一、痛点为什么手动传参让人头大 在 NestJS 里如果一个 Service 需要用到当前请求的用户 IP用户角色租户 ID常见做法是把request或用户对象作为参数从 Controller 一路传给 Service、再传给 Repository或者使用REQUEST作用域 Provider导致大量 Provider 退化为请求级内存开销上升日志里想带上 Request ID只能靠口头约定在每个方法签名里塞参数。手动传参三大问题签名污染——业务方法被迫携带与业务无关的参数作用域失控——REQUEST作用域 Provider 滥用带来性能与内存问题扩展困难——WebSocket、定时任务、队列消费者等场景根本拿不到request对象。nestjs-cls 的思路是借助AsyncLocalStorage把上下文数据存进一块随调用链自动流转的共享存储任何被调用的代码都能直接读写无需传参。二、原理速览AsyncLocalStorage 是如何工作的 ⚙️延续本地存储CLS提供了一个贯穿整个函数/回调调用链的公共存储空间应用入口调用cls.run()或enter()初始化上下文之后同一回调链中任何地方都能通过cls.set()/cls.get()读写同一份数据不同请求之间的上下文互相隔离天然安全。核心服务接口定义在 packages/core/src/cls.service.ts模块初始化器位于 packages/core/src/lib/cls-initializers/包含中间件、守卫、拦截器三种挂载方式。三、一键安装最快配置方法 用你喜欢的包管理器安装npm install nestjs-cls在根模块中注册ClsModule并自动挂载中间件为所有路由包裹一层共享 CLS 上下文Module({ imports: [ ClsModule.forRoot({ global: true, middleware: { mount: true }, }), ], }) export class AppModule {}模块注册逻辑见 packages/core/src/lib/cls-module/cls.module.ts。至此上下文已就绪10 分钟接入完成 80%四、读写上下文Interceptor 存、Service 取 以记录并共享用户 IP为例整体分三步1️⃣ 在拦截器中写入注入ClsService把request里的 IP 存入上下文Injectable() export class UserIpInterceptor implements NestInterceptor { constructor(private readonly cls: ClsService) {} intercept(context: ExecutionContext, next: CallHandler) { const request context.switchToHttp().getRequest(); this.cls.set(ip, request.connection.remoteAddress); return next.handle(); } }2️⃣ 挂到 Controller 上也可用APP_INTERCEPTOR全局绑定。3️⃣ 在 Service 中直接读取Injectable() export class AppService { constructor(private readonly cls: ClsService) {} sayHello() { const userIp this.cls.get(ip); // 无需任何传参 return Hello ${userIp}!; } }注意AppService不需要改成REQUEST作用域单例 Provider 照样能拿到当前请求的数据——这就是 CLS 的价值。五、高频场景Request ID 日志追踪 日志追踪是 CLS 最经典的应用。开启generateId: true后中间件会自动为每个请求生成 ID可自定义idGenerator例如优先读取X-Request-Id请求头ClsModule.forRoot({ middleware: { mount: true, generateId: true, idGenerator: (req) req.headers[X-Request-Id] ?? uuid(), }, })之后任何位置的日志器只需调用cls.getId()所有日志自动带上同一个关联 ID排查线上问题效率翻倍。更多用法参考官方文档 docs/docs/03_features-and-use-cases/01_request-id.md。其他典型场景场景说明 用户身份贯穿请求认证后把用户信息存入 CLS深层 Service 随处可取 多租户动态连接把租户数据库连接放入上下文全链路自动切换 事务跨服务传播搭配事务插件无侵入地把数据库事务传给下游服务 非 HTTP 场景WebSocket、定时任务、队列消费者中替代 REQUEST 作用域六、进阶Proxy Providers 替代 REQUEST 作用域 nestjs-cls 还提供了Proxy Providers代理 Provider通过装饰器声明依赖关系模块会在运行时按需把 Provider绑定到当前 CLS 上下文真正替代REQUEST作用域。相关实现位于 packages/core/src/lib/proxy-provider/入门文档见 docs/docs/03_features-and-use-cases/06_proxy-providers.md。七、总结10 分钟收益长期有效 ✅步骤耗时动作11 分钟npm install nestjs-cls22 分钟ClsModule.forRoot({ global: true, middleware: { mount: true } })33 分钟Interceptor 写上下文Service 读上下文44 分钟按需开启 Request ID 生成与插件核心收获✅ 基于 Node.js 原生AsyncLocalStorage零第三方运行时依赖仅依赖nestjs/*✅ 单例 Provider 即可访问请求级数据内存与性能双友好✅ 上下文自动隔离多线程/并发请求互不串扰✅ 可插拔架构事务传播、Proxy Providers 等能力按需扩展。 上手之后建议继续阅读官方文档中的 快速开始、上下文初始化方式 与 安全性考量把 nestjs-cls 用到极致【免费下载链接】nestjs-clsA continuation-local storage (async context) module compatible with NestJSs dependency injection.项目地址: https://gitcode.com/gh_mirrors/ne/nestjs-cls创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表