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

如何使用http-proxy-middleware记录代理的请求与响应体?

解决http-proxy-middleware记录请求/响应体的问题

我来帮你搞定这个问题!你现在遇到的核心问题是:req 和 proxyRes 都是Node.js的可读流,默认情况下数据会直接流过代理,不会缓存下来,所以你得手动收集这些流的数据,同时还要保证数据能正常传递到目标服务(请求体)和客户端(响应体),不能搞断流了。

一、先搞定请求体:在代理前提前收集

因为http-proxy会直接消费req这个流,所以必须在proxy中间件之前就把请求体收集好。你可以加一个自定义中间件来做这件事:

// 专门用来收集请求体的中间件,要放在proxy中间件前面
app.use('/proxy/:service/', (req, res, next) => {
  let bodyChunks = [];
  // 监听流的data事件,把每个数据块存起来
  req.on('data', chunk => {
    bodyChunks.push(chunk);
  })
  // 流结束时,把所有数据块拼接成完整的请求体
  .on('end', () => {
    // 转成utf8字符串(如果是二进制数据,就保留Buffer不要转)
    req.rawBody = Buffer.concat(bodyChunks).toString('utf8');
    next(); // 继续走后面的proxy中间件
  });
});

这样后面不管是在onProxyReq还是onProxyRes里,都能通过req.rawBody拿到完整的请求体了。

二、再处理响应体:在onProxyRes里收集并转发

对于响应体来说,onProxyRes确实是最合适的钩子,但要注意:收集完响应体后,必须把数据重新写回客户端的res对象,不然客户端会一直等响应收不到。

我推荐用concat-stream来简化流的拼接(先装个依赖:npm install concat-stream),代码更简洁:

const concat = require('concat-stream');

app.use('/proxy/:service/', proxy({
  pathRewrite: function(path, req){ /* 你的原有逻辑 */ },
  router: function(req) { /* 你的原有逻辑 */ },
  onProxyReq: function(proxyReq, req, res) {
    // 这里可以记录请求的详细信息
    log(`请求URL: ${req.originalUrl}`);
    log(`请求体: ${req.rawBody || '无请求体'}`);
  },
  onProxyRes: function(proxyRes, req, res) {
    // 用concat-stream把响应流拼接到一起
    proxyRes.pipe(concat(responseBuffer => {
      const responseBody = responseBuffer.toString('utf8');
      // 记录响应信息
      log(`请求URL: ${req.originalUrl}`);
      log(`响应状态码: ${proxyRes.statusCode}`);
      log(`响应体: ${responseBody}`);
      
      // 把响应体重新写回给客户端,不然客户端收不到
      res.setHeader('Content-Length', responseBuffer.length);
      res.end(responseBuffer);
    }));
    // 先暂停原始的响应流,避免数据丢失
    proxyRes.pause();
  }
}));

要是不想装额外依赖,手动拼接也可以:

onProxyRes: function(proxyRes, req, res) {
  let responseChunks = [];
  proxyRes.on('data', chunk => {
    responseChunks.push(chunk);
  });
  proxyRes.on('end', () => {
    const responseBuffer = Buffer.concat(responseChunks);
    const responseBody = responseBuffer.toString('utf8');
    // 记录日志
    log(`请求URL: ${req.originalUrl}`);
    log(`响应状态码: ${proxyRes.statusCode}`);
    log(`响应体: ${responseBody}`);
    
    // 转发响应给客户端
    res.setHeader('Content-Length', responseBuffer.length);
    res.end(responseBuffer);
  });
  proxyRes.pause();
}

三、关于onProxyRes是不是最佳方式

对于响应体的处理,onProxyRes绝对是http-proxy-middleware提供的最合适的钩子——它是代理服务器收到目标服务响应后的第一个回调点,能完整拿到响应的状态码、响应头和响应体。而请求体必须在proxy之前处理,因为proxy会直接消费req流,晚一步就拿不到数据了。

一些要注意的细节

  • 如果你的代理要处理二进制数据(比如图片、文件),别直接转成字符串,保留Buffer就行,记录的时候可以转成base64或者直接用二进制模式写入日志文件。
  • 如果要处理超大的请求/响应,把整个body攒到内存里可能会有性能问题,这时候建议直接用流式写入日志,不要先拼成完整的字符串。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 07:24:53