如何在Fastify中记录响应体?响应对象未暴露响应体
如何在Fastify中记录响应体
确实,Fastify默认不会把响应体暴露给日志序列化器里的res对象——因为响应是流式传输的,为了性能考虑,框架不会自动缓存整个响应体。不过我们可以通过Fastify的钩子机制来实现这个需求,下面是两种可行的方案:
方案一:使用onSend钩子捕获响应体
onSend钩子会在响应即将发送给客户端前触发,此时我们可以获取到响应体的payload,并将其附加到Node.js原生的res对象上,这样日志序列化器就能访问到它了。
const fastify = require('fastify')({ logger: { serializers: { res(res) { return { statusCode: res.statusCode, body: res.body // 现在可以拿到响应体了 }; } } } }); // 添加onSend钩子来捕获并存储响应体 fastify.addHook('onSend', async (request, reply, payload) => { // payload可能是Buffer或字符串,转成字符串方便日志记录 if (payload) { reply.res.body = typeof payload === 'string' ? payload : payload.toString(); } // 必须返回payload,否则客户端会收不到响应 return payload; }); // 测试路由 fastify.get('/', async (request, reply) => { return { message: 'Hello Fastify!' }; }); fastify.listen({ port: 3000 }, (err) => { if (err) { fastify.log.error(err); process.exit(1); } });
注意事项
- 这种方式会将整个响应体加载到内存中,如果你的服务处理大文件或大响应(比如超过100MB),可能会导致内存占用过高,建议只在开发环境使用,或者添加响应体大小过滤逻辑。
- 如果响应是流式的(比如
reply.send(fs.createReadStream('large-file.txt'))),payload会是null,这种场景下需要额外监听流的data事件来收集内容,但同样要注意内存开销问题。
方案二:在业务逻辑中主动记录响应体
如果你的响应都是通过reply.send()发送的JSON对象或简单字符串,可以在发送前直接将响应体传递给日志,这种方式更轻量化,不需要钩子:
const fastify = require('fastify')({ logger: true }); fastify.get('/', async (request, reply) => { const responseBody = { message: 'Hello Fastify!' }; // 主动记录响应体 request.log.info({ responseBody }, 'Sending response'); return responseBody; });
这种方式适合响应体较小且可控的场景,不会有额外的内存开销。
内容的提问来源于stack exchange,提问作者cyberwombat
相关产品推荐
相关产品推荐

