@lark-apaas/nestjs-common
v0.1.0
Published
Common NestJS utilities
Readme
@lark-apaas/nestjs-common
提供可复用的 NestJS 通用能力与类型定义,当前内置请求级上下文服务 RequestContextService,用于在一次 HTTP 请求的生命周期内安全地读写上下文数据(如请求 ID、路径、方法、用户/租户/应用信息、IP 等)。
特性
- 请求级上下文(AsyncLocalStorage)
- 在同一请求链路中安全传递上下文数据
- 支持在中间件、拦截器、服务、控制器中读写
- 纯粹的 NestJS 通用包
- 不依赖具体业务模块(例如日志、可观测),便于复用
安装
yarn add @lark-apaas/nestjs-common或使用 npm:
npm install @lark-apaas/nestjs-common环境要求
- Node.js >= 18.0.0
- NestJS >= 10.4.20
快速开始
1. 在顶层模块中注册为单例 Provider(推荐)
// app.module.ts
import { Module } from '@nestjs/common';
import { RequestContextService } from '@lark-apaas/nestjs-common';
@Module({
providers: [RequestContextService],
exports: [RequestContextService],
})
export class AppModule {}建议在应用的根模块或全局模块中注册为单例,以确保整个应用共享同一个
AsyncLocalStorage实例。
2. 在中间件入口写入请求上下文
// observable-context.middleware.ts(示例)
import { Injectable, NestMiddleware } from '@nestjs/common';
import type { Request, Response, NextFunction } from 'express';
import { randomUUID } from 'crypto';
import { RequestContextService } from '@lark-apaas/nestjs-common';
@Injectable()
export class ObservableContextMiddleware implements NestMiddleware {
constructor(private readonly reqCtx: RequestContextService) {}
use(req: Request & { userContext?: any }, res: Response, next: NextFunction) {
const requestId = (req.headers['x-tt-log-id'] as string) || (req.headers['x-request-id'] as string) || randomUUID();
const path = req.originalUrl ?? req.url;
const uc = req.userContext ?? {};
res.setHeader('x-log-trace-id', requestId);
this.reqCtx.run(
{
requestId,
path,
method: req.method,
userId: uc.userId,
tenantId: uc.tenantId,
appId: uc.appId,
ip: (req.ip as string) ?? undefined,
},
() => next(),
);
}
}3. 在任意位置读取上下文
import { Injectable } from '@nestjs/common';
import { RequestContextService } from '@lark-apaas/nestjs-common';
@Injectable()
export class DemoService {
constructor(private readonly reqCtx: RequestContextService) {}
doSomething() {
const ctx = this.reqCtx.getContext();
// 或者精确获取某个键
const requestId = this.reqCtx.get('requestId');
// ... 使用上下文执行你的逻辑
return { requestId, path: ctx?.path, method: ctx?.method };
}
}API 概览
RequestContextService 源码位置:packages/server/nestjs-common/src/request-context.service.ts
run(context, callback):在AsyncLocalStorage中启动一次上下文存储并执行回调。- 参考:packages/server/nestjs-common/src/request-context.service.ts:15-20
setContext(partial):在当前上下文中合并写入部分字段。- 参考:packages/server/nestjs-common/src/request-context.service.ts:22-30
getContext():读取当前完整上下文。- 参考:packages/server/nestjs-common/src/request-context.service.ts:32-34
get(key):读取当前上下文中的特定键。- 参考:packages/server/nestjs-common/src/request-context.service.ts:36-38
RequestContextState 默认字段:
interface RequestContextState {
requestId: string;
path?: string;
method?: string;
userId?: string;
appId?: string;
tenantId?: string;
ip?: string;
[key: string]: unknown;
}与其他模块的协作建议
- 与日志/可观测模块协作
- 在 HTTP 入口(中间件)调用
run(...)写入上下文; - 在日志或可观测的记录点读取上下文并合并到结构化日志或埋点数据中。
- 在 HTTP 入口(中间件)调用
- 仅白名单传递敏感信息
- 避免直接把所有请求头写入上下文,建议只传递必要字段(如 trace-id、user-id、tenant-id、app-id)。
TypeScript 支持
本包使用 TypeScript 编写并导出完整类型:
export { RequestContextService, type RequestContextState } from '@lark-apaas/nestjs-common';如需在 Express.Request 上扩展 userContext 等业务字段,请在你自己的项目中通过 declare global 进行类型声明扩展。
许可证
MIT
关键字
- nestjs
- common
- context
- als
- server
- typescript
