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

Express中间件无法记录JSON请求?求技术排查方案

问题根源

你遇到的核心问题是请求体流只能被读取一次:

  • 发送合法JSON格式的POST请求时,express.json()(或body-parser.json())中间件会优先完整读取请求体流并解析为req.body,此时流已被耗尽。如果你的Morgan中间件在express.json()之后执行,尝试读取请求体时会获取不到内容,导致你误以为请求没被记录。
  • 非JSON格式的DELETE请求:express.json()尝试解析失败,不会完全消耗请求体流,后续Morgan能正常读取流内容完成记录。
  • 格式错误的JSON DELETE请求:express.json()解析失败后直接触发错误处理流程,返回JSON语法错误响应,此时请求体流可能还未被完全消耗,或者错误响应触发了Morgan的日志记录逻辑。
解决方案

要解决这个问题,需要先缓存请求体的原始内容,让express.json()和Morgan都能访问到请求数据,具体步骤如下:

  1. 添加请求体缓存中间件
    在所有解析中间件(如express.json())之前,添加一个自定义中间件,将原始请求体缓存到req.rawBody中:
app.use((req, res, next) => {
  let rawBody = '';
  req.on('data', (chunk) => {
    rawBody += chunk.toString();
  });
  req.on('end', () => {
    req.rawBody = rawBody;
    next();
  });
});
  1. 配置express.json()
    之后再启用JSON解析中间件,此时它会从缓存的原始内容中解析,不会影响后续Morgan的读取:
app.use(express.json());
  1. 修改Morgan配置使用缓存的请求体
    自定义Morgan的token或日志格式,直接使用req.rawBody来获取原始请求体,并存入全局变量:
const morgan = require('morgan');

// 自定义请求体token
morgan.token('raw-body', (req) => req.rawBody || '');

app.use(morgan((tokens, req, res) => {
  // 将请求信息存入全局变量
  global.requests = global.requests || [];
  global.requests.push({
    method: tokens.method(req, res),
    url: tokens.url(req, res),
    body: tokens['raw-body'](req, res),
    status: tokens.status(req, res),
    timestamp: tokens.date(req, res, 'iso')
  });

  // 可选:返回日志字符串用于控制台输出
  return [
    tokens.date(req, res, 'iso'),
    tokens.method(req, res),
    tokens.url(req, res),
    tokens.status(req, res),
    tokens['raw-body'](req, res)
  ].join(' | ');
}));
额外注意事项
  • 全局变量global.requests仅适合本地测试,生产环境建议使用内存数据库(如Redis)或文件存储,避免进程重启丢失数据。
  • 如果你的项目中使用了其他解析中间件(如express.urlencoded()),同样需要保证缓存中间件在它们之前执行。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 01:58:11