如何编写包裹所有HTTP请求的NestJS回调函数
实现全局HTTP请求前后日志(含耗时统计)
针对你遇到的问题——现有拦截器或中间件只能捕获请求开始,无法在响应完成时打印日志,以下是两种可行方案:
方案一:使用Nest拦截器(跨平台友好)
Nest的拦截器可以通过RxJS的tap操作符,在请求处理流的开始和结束阶段注入逻辑。当路由处理完成并返回响应时,tap会触发回调,此时就能计算耗时。
代码实现
创建一个日志拦截器:
import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common'; import { Observable } from 'rxjs'; import { tap } from 'rxjs/operators'; @Injectable() export class LoggingInterceptor implements NestInterceptor { intercept(context: ExecutionContext, next: CallHandler): Observable<any> { const startTime = Date.now(); const request = context.switchToHttp().getRequest(); console.log(`${startTime}ms HTTP request start ${request.method} ${request.url}`); // 处理完请求后执行的逻辑 return next.handle().pipe( tap(() => { const elapsed = Date.now() - startTime; console.log(`${elapsed}ms Response delivered`); }), ); } }
全局注册
在main.ts中全局启用该拦截器:
import { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; import { LoggingInterceptor } from './logging.interceptor'; async function bootstrap() { const app = await NestFactory.create(AppModule); app.useGlobalInterceptors(new LoggingInterceptor()); await app.listen(3000); } bootstrap();
方案二:使用Express中间件(精准捕获响应完成时机)
如果你的项目基于Express,可以直接监听响应对象的finish事件——这个事件会在响应完全发送给客户端时触发,比拦截器的tap更精准(比如流式响应场景)。
代码实现
创建日志中间件:
import { Injectable, NestMiddleware } from '@nestjs/common'; import { Request, Response, NextFunction } from 'express'; @Injectable() export class LoggingMiddleware implements NestMiddleware { use(req: Request, res: Response, next: NextFunction) { const startTime = Date.now(); console.log(`${startTime}ms HTTP request start ${req.method} ${req.url}`); // 监听响应完成事件 res.on('finish', () => { const elapsed = Date.now() - startTime; console.log(`${elapsed}ms Response delivered`); }); next(); } }
全局注册
在AppModule中配置中间件,对所有路由生效:
import { Module, NestModule, MiddlewareConsumer } from '@nestjs/common'; import { LoggingMiddleware } from './logging.middleware'; @Module({}) export class AppModule implements NestModule { configure(consumer: MiddlewareConsumer) { consumer.apply(LoggingMiddleware).forRoutes('*'); } }
方案对比
- 拦截器:Nest框架的上层抽象,支持跨平台(切换到Fastify无需修改代码),适合普通JSON响应场景。
- Express中间件:依赖Express生态,能精准捕获响应发送完成的时机,适合流式响应或需要严格监控响应生命周期的场景。
内容的提问来源于stack exchange,提问作者Paku
相关产品推荐
相关产品推荐

