You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Node.js中如何记录响应体?Morgan中间件获取res.body遇阻

解决Morgan无法获取响应体的方案

Morgan 默认不会自动把响应内容挂载到 res.body 上,所以直接读取 res.body 会得到 undefined。要获取响应体,得先通过中间件劫持 Express 的响应发送方法,把响应内容暂存到 res.body 中。

步骤1:添加响应体拦截中间件

在 Morgan 中间件之前,添加自定义中间件劫持 res.json 和 res.send 方法,提前保存响应内容:

app.use((req, res, next) => {
  // 保存原始的json方法
  const originalJson = res.json;
  res.json = function(data) {
    // 将响应内容存入res.body
    res.body = data;
    // 调用原始方法发送响应
    return originalJson.call(this, data);
  };

  // 保存原始的send方法
  const originalSend = res.send;
  res.send = function(data) {
    // 处理不同类型的响应数据
    if (typeof data === 'object' && data !== null) {
      res.body = data;
    } else {
      try {
        // 尝试解析为JSON格式,失败则存原始值
        res.body = JSON.parse(data);
      } catch (e) {
        res.body = data;
      }
    }
    return originalSend.call(this, data);
  };
  next();
});

步骤2:修改Morgan响应体Token

现在 res.body 已被赋值,自定义Token可以正常读取:

morgan.token('sbody', (res) => {
  // 兜底处理res.body不存在的情况
  return JSON.stringify(res.body || {});
});

完整示例代码

将中间件与Morgan配置结合使用:

const express = require('express');
const morgan = require('morgan');
const app = express();

// 先解析请求体(必须在Morgan之前)
app.use(express.json());
app.use(express.urlencoded({ extended: true }));

// 响应体拦截中间件
app.use((req, res, next) => {
  const originalJson = res.json;
  res.json = function(data) {
    res.body = data;
    return originalJson.call(this, data);
  };

  const originalSend = res.send;
  res.send = function(data) {
    if (typeof data === 'object' && data !== null) {
      res.body = data;
    } else {
      try {
        res.body = JSON.parse(data);
      } catch (e) {
        res.body = data;
      }
    }
    return originalSend.call(this, data);
  };
  next();
});

// 自定义Morgan Tokens
morgan.token('qbody', (req) => {
  return JSON.stringify(req.body || {});
});

morgan.token('sbody', (res) => {
  return JSON.stringify(res.body || {});
});

// 使用自定义格式的Morgan日志
app.use(morgan(':method :url :status :response-time ms - Request Body: :qbody - Response Body: :sbody'));

// 测试路由
app.post('/test', (req, res) => {
  res.json({ message: 'success', received: req.body });
});

app.listen(3000, () => {
  console.log('Server running on port 3000');
});

注意事项

  • 响应体拦截中间件必须放在Morgan中间件之前,确保先完成方法劫持。
  • 必须先通过 express.json() 或 express.urlencoded() 解析请求体,否则 req.body 也会是 undefined。
  • 如果应用使用了 res.sendFile 这类发送文件流的方法,无需劫持(这类内容不适合存入 res.body),按需扩展劫持逻辑即可。

内容的提问来源于stack exchange,提问作者Venkat Cpr

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 14:12:06