使用FastifyAdapter的NestJS应用无法在中间件中获取请求体
问题原因
- 类型不匹配:你使用Fastify作为HTTP适配器,但中间件中导入的是Express的
Request类型,二者请求对象的结构和解析逻辑不完全一致。 - 执行时机问题:Nest的中间件执行在Fastify内置的请求体解析逻辑之前,Fastify默认仅在路由处理阶段才会完成请求体的解析,因此中间件执行时
body还未被挂载到请求对象上,自然返回undefined。
解决方案
这里提供两种可行的实现方式,可根据需求选择:
方案1:改用Nest拦截器实现全局日志(更推荐)
拦截器的执行时机在请求体解析完成之后,同时适配Express和Fastify双框架,不需要额外调整适配器配置,示例代码如下:
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 request = context.switchToHttp().getRequest(); const { httpVersion, headers, method, url, params, query, body } = request; console.log('Request Body...', body); const now = Date.now(); return next .handle() .pipe( tap(() => console.log(`请求耗时 ${Date.now() - now}ms`)), ); } }
然后在main.ts中全局注册拦截器即可,原有中间件相关代码可以直接删除:
async function bootstrap() { const app = await NestFactory.create<NestFastifyApplication>( AppModule, new FastifyAdapter() ); // 全局注册拦截器 app.useGlobalInterceptors(new LoggingInterceptor()); await app.listen(3000); } bootstrap()
方案2:使用Fastify原生钩子实现日志
如果希望更贴近Fastify的原生逻辑,可以直接注册Fastify的preHandler钩子,该钩子在请求体解析完成后执行,直接在main.ts中添加如下代码即可:
async function bootstrap() { const app = await NestFactory.create<NestFastifyApplication>( AppModule, new FastifyAdapter() ); // 注册Fastify preHandler钩子 app.getHttpAdapter().getInstance().addHook('preHandler', (request, reply, done) => { const { httpVersion, headers, method, url, params, query, body } = request; console.log('Request Body...', body); done(); }); await app.listen(3000); } bootstrap()
内容的提问来源于stack exchange,提问作者Abhishek Chaniyara
相关产品推荐
相关产品推荐

