NestJS中如何在Pino中间件外部获取请求ID(reqId)
获取请求ID并存入数据库的两种方案
方案一:直接从请求对象传递reqId
这种方法简单直接,通过控制器把请求对象中的reqId传递给服务层。
1. 修改控制器,传递reqId
import { Controller, Post, Req } from '@nestjs/common'; import { MyService } from './app.service'; @Controller() export class AppController { constructor(private readonly myService: MyService) {} @Post('activity') async createActivity(@Req() req) { // pino会把genReqId生成的ID挂载到req.id上 await this.myService.saveActivity(req.id); } }
2. 服务层接收并使用reqId
import { Injectable, Logger } from '@nestjs/common'; @Injectable() export class MyService { private readonly logger = new Logger(MyService.name); async saveActivity(requestId: string) { this.logger.log("saving user activity"); // 将reqId存入数据库字段 await userActivityRepo.save({ ...rest, request_id: requestId }); } }
方案二:使用AsyncLocalStorage全局共享reqId
如果不想在控制器和服务层之间显式传递reqId,可以用NestJS的AsyncLocalStorage(ALS)在整个请求链路中共享reqId。
1. 创建ALS服务
import { Injectable, AsyncLocalStorage } from '@nestjs/common'; @Injectable() export class AlsService { private readonly als = new AsyncLocalStorage(); runWithId(id: string, callback: () => void) { return this.als.run({ requestId: id }, callback); } getRequestId(): string { return this.als.getStore()?.requestId; } }
2. 编写中间件存入reqId到ALS
import { Injectable, NestMiddleware } from '@nestjs/common'; import { AlsService } from '../als/als.service'; @Injectable() export class RequestIdMiddleware implements NestMiddleware { constructor(private readonly alsService: AlsService) {} use(req: any, res: any, next: () => void) { // 从请求对象获取pino生成的reqId const requestId = req.id; // 将reqId存入ALS,后续链路可全局访问 this.alsService.runWithId(requestId, next); } }
3. 在模块中注册中间件和ALS服务
import { Module, MiddlewareConsumer } from '@nestjs/common'; import { LoggerModule } from 'nestjs-pino'; import { v4 as uuid } from 'uuid'; import { AlsService } from './als/als.service'; import { RequestIdMiddleware } from './middlewares/request-id.middleware'; import { MyService } from './app.service'; import { AppController } from './app.controller'; @Module({ imports: [ LoggerModule.forRoot({ pinoHttp: { genReqId: (req: any) => { return req.headers.req_id || uuid(); }, base: undefined, quietReqLogger: true, timestamp: false, }, }), ], controllers: [AppController], providers: [MyService, AlsService], }) export class AppModule { configure(consumer: MiddlewareConsumer) { // 全局应用中间件 consumer.apply(RequestIdMiddleware).forRoutes('*'); } }
4. 服务层从ALS获取reqId
import { Injectable, Logger } from '@nestjs/common'; import { AlsService } from './als/als.service'; @Injectable() export class MyService { private readonly logger = new Logger(MyService.name); constructor(private readonly alsService: AlsService) {} async saveActivity() { // 从ALS获取当前请求的reqId const requestId = this.alsService.getRequestId(); this.logger.log("saving user activity"); await userActivityRepo.save({ ...rest, request_id: requestId }); } }
内容的提问来源于stack exchange,提问作者Zain Khan
相关产品推荐
相关产品推荐

