解析请求体后NodeJS http-proxy无响应,求解决方案
解决读取请求体后http-proxy代理无响应的问题
核心原因是:Node.js的请求对象是可读流,一旦被读取完毕,流就会处于结束状态,http-proxy无法再从中读取数据转发给目标服务,导致代理请求缺失请求体,目标服务无响应。
方案一:读取请求体后重建可读流
读取完请求体的buffer后,创建一个PassThrough流,将原始buffer写入新流,再替换原请求对象的流相关方法,让http-proxy能从新流中读取数据。
const express = require('express'); const httpProxy = require('http-proxy'); const { PassThrough } = require('stream'); const proxy = httpProxy.createProxyServer({}); const app = express(); app.post('*', async function(req, res) { // 读取原始请求体 const buffers = []; for await (const chunk of req) { buffers.push(chunk); } const requestBuffer = Buffer.concat(buffers); const bodyData = JSON.parse(requestBuffer.toString()); console.log(bodyData); // 创建新的可读流,写入原始请求体数据 const passThroughStream = new PassThrough(); passThroughStream.end(requestBuffer); // 替换请求对象的流方法,让proxy能读取新流 req.pipe = passThroughStream.pipe.bind(passThroughStream); req.read = passThroughStream.read.bind(passThroughStream); req.on = passThroughStream.on.bind(passThroughStream); req.emit = passThroughStream.emit.bind(passThroughStream); req.readable = true; // 根据业务逻辑选择代理目标 const target = bodyData.description.includes('payment') ? 'http://localhost:3600/payment' : 'http://localhost:3601/order'; proxy.web(req, res, { target }); }); const server = app.listen(3602);
方案二:使用body-parser的raw模式解析
通过body-parser.raw()直接获取请求体的buffer,再重建流转发,这种方式更简洁,适合需要解析任意类型请求体的场景。
const express = require('express'); const httpProxy = require('http-proxy'); const bodyParser = require('body-parser'); const { PassThrough } = require('stream'); const proxy = httpProxy.createProxyServer({}); const app = express(); // 用raw模式解析所有类型的请求体,保留原始buffer app.use(bodyParser.raw({ type: '*/*', limit: '10mb' })); app.post('*', function(req, res) { try { const bodyData = JSON.parse(req.body.toString()); console.log(bodyData); // 创建新流并写入原始请求体 const passThroughStream = new PassThrough(); passThroughStream.end(req.body); // 替换请求流方法 req.pipe = passThroughStream.pipe.bind(passThroughStream); req.read = passThroughStream.read.bind(passThroughStream); req.on = passThroughStream.on.bind(passThroughStream); req.emit = passThroughStream.emit.bind(passThroughStream); req.readable = true; // 选择代理目标 const target = bodyData.description.includes('payment') ? 'http://localhost:3600/payment' : 'http://localhost:3601/order'; proxy.web(req, res, { target }); } catch (err) { // 处理JSON解析失败的情况 res.status(400).send('Invalid request body'); } }); const server = app.listen(3602);
注意事项
- 根据请求体大小调整
limit参数,避免因请求体过大导致解析失败 - 无需修改
Content-Length请求头,因为转发的是原始buffer,长度与原请求一致 - 增加错误处理逻辑(如JSON解析失败),避免请求挂起
内容的提问来源于stack exchange,提问作者Sam
相关产品推荐
相关产品推荐

