首页  编辑  

类似Java/Springboot的ThreadLocal变量使用: AsyncLocalStorage

Tags: /Node & JS/   Date Created:
参考资料: 异步本地存储 |NestJS - 渐进式 Node.js 框架

我们可以使用AsyncLocalStorage,实现类似Java语言中的ThreadLocal变量,从而在整个线程范围内扩散对象和数据,而无需在方法参数列表中传递对象。例如实现类似 SpringBoot中RequestContextHolder类似的效果。

首先创建 als.module.ts,这个是类似实现一个单例的对象,该对象在单次前端请求整个生命期间有效:

  1. import { Inject, Injectable, Module } from '@nestjs/common';
  2. import { AsyncLocalStorage } from 'async_hooks';

  3. @Module({
  4.     providers: [
  5.         {
  6.             provide: AsyncLocalStorage,
  7.             useValue: new AsyncLocalStorage(),
  8.         },
  9.     ],
  10.     exports: [AsyncLocalStorage],
  11. })
  12. export class AlsModule { }
其次,修改 app.module.ts,路由拦截所有请求,并处理相关数据,然后存入 storage:
  1. import { AlsModule } from './als.module';
  2. import { AlsLogger } from 'AlsLogger';
  3. @Module({
  4.   imports: [
  5.     AlsModule,
  6.     //...
  7.   ],
  8.   // ...
  9. })
  10. export class AppModule implements NestModule {
  11.   private readonly logger: Logger = new AlsLogger("AppModule");
  12.   constructor(
  13.     private readonly als: AsyncLocalStorage<object>
  14.   ) { }
  15.   configure(consumer: MiddlewareConsumer) {
  16.     //...
  17.     consumer.apply((req, res, next) => {
  18.       const token = req.headers['accesstoken'];
  19.       let info = "";
  20.       if (token) {
  21.         const headers = JSON.parse(token);
  22.         info = this.logger.genInfo(headers.a, headers.b, headers.c, headers.d);
  23.       } else {
  24.         info = req.headers['token'] || req.headers['access_token'] || req.headers['access-token'] || this.logger.genInfo("-9""-9""-9""-9");
  25.       }
  26.       const store = { info: info };
  27.       this.als.run(store, () => next());
  28.     }).forRoutes('*');
  29.   }
  30. }

最后,在任意地方使用:

  1. import { AsyncLocalStorage } from 'async_hooks';
  2. @Injectable()
  3. export class XxxxService {
  4.   constructor(
  5.     private readonly als: AsyncLocalStorage<object>,
  6.     // ....
  7.   ) {}
  8.   async xxx(a: string) {
  9.     const passAlong = this.als.getStore()['passAlong'as string;
  10.     console.log("我们可以拿到 pass along: ", passAlong);
  11.     // ...
  12.   }
  13. }

这样我们就可以实现线程全局变量了。