Search K
Appearance
Appearance
公司的一个老项目使用http-proxy-middleware
代理转发本地接口,在对接一个SSE
流式接口的时候发现转发总是很慢,如果直接在降级浏览器中请求真实地址发现响应速度很快,由此断定本地开发慢的原因大概率是代理库引起的问题。
经过一番和Cursor
以及豆包的沟通,终于修复了问题,特此记录下来
proxy.js
const proxy = require("http-proxy-middleware");
module.exports = function(app) {
app.use(
proxy('/ai_agent', {
target: 'http://xxx.xxxx.xxxxx',
secure: false,
changeOrigin: true,
pathRewrite: { '^/ai_agent': '' },
buffer: false,
proxyTimeout: 300000,
timeout: 300000,
compress: false,
followRedirects: false,
selfHandleResponse: true, // 完全自己处理响应,避免重复
onProxyReq: (proxyReq, req, res) => {
const requestId = Date.now() + Math.random().toString(36).substr(2, 9);
req.requestId = requestId;
console.log(`[${requestId}] 代理请求: ${req.method} ${req.url}`);
},
onProxyRes: (proxyRes, req, res) => {
// 设置SSE响应头
res.setHeader('Content-Type', 'text/event-stream');
res.setHeader('Cache-Control', 'no-cache');
res.setHeader('Connection', 'keep-alive');
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Headers', 'Cache-Control');
// 删除可能影响SSE的响应头
delete proxyRes.headers['content-length'];
delete proxyRes.headers['transfer-encoding'];
delete proxyRes.headers['content-encoding'];
// 防止重复监听
if (proxyRes._sseHandled) return;
proxyRes._sseHandled = true;
let chunkCount = 0;
// 直接监听数据事件并立即转发,但防止重复
proxyRes.on('data', (chunk) => {
chunkCount++;
// 立即写入响应,确保实时性
res.write(chunk);
// 强制刷新缓冲区
if (res.flush) res.flush();
});
proxyRes.on('end', () => {
res.end();
});
proxyRes.on('error', (err) => {
res.end();
});
}
})
);
};
关键点在于res
的响应方式,使用res.write(chunk)
可以立即写入确保实时性,但是有可能会重复写入两次chunk
,可以添加了一个_sseHandled
变量解决这个问题。
最开始满的根本原因是使用了proxyRes.pipe(res)
将数据写回,代理服务器接受到了所有的消息后才会一次性发回,这就导致了流一直没有响应。