NodeJS代理EventSource(SSE)至本地后端连接失败问题排查
解决方案:生产环境下SSE代理返回React HTML的问题
核心原因分析
生产环境下请求被Express的React静态资源路由优先捕获,而非转发到后端;或代理配置未适配SSE长连接特性。
1. 调整Express路由顺序(最常见原因)
开发环境create-react-app的Webpack Dev Server会优先处理/api代理请求,但生产环境Express默认会先匹配静态资源和*路由,导致/api请求被React的单页路由捕获,返回index.html。
解决方法:把代理配置放在静态资源和*路由之前:
const express = require('express'); const { createProxyMiddleware } = require('http-proxy-middleware'); const path = require('path'); const app = express(); // 1. 先配置API代理(必须放在静态资源路由之前) app.use('/api', createProxyMiddleware({ target: 'https://localhost:9047', changeOrigin: true, // 如果后端接口没有/api前缀,需要重写路径 pathRewrite: { '^/api': '' }, // 禁用证书验证(如果后端是自签名HTTPS证书) secure: false, })); // 2. 再配置React静态资源 app.use(express.static(path.join(__dirname, 'build'))); // 3. 最后处理React单页路由 app.get('*', (req, res) => { res.sendFile(path.join(__dirname, 'build', 'index.html')); }); app.listen(3000);
2. 适配SSE的代理特殊配置
SSE是HTTP长连接,需要确保代理不修改响应头、不中断连接:
在代理配置中添加SSE专属处理:
app.use('/api', createProxyMiddleware({ // ...其他基础配置 onProxyRes: (proxyRes, req, res) => { // 强制保留后端返回的text/event-stream类型 proxyRes.headers['Content-Type'] = 'text/event-stream'; // 禁用缓存,避免浏览器缓存SSE响应 proxyRes.headers['Cache-Control'] = 'no-cache, no-store, must-revalidate'; proxyRes.headers['Pragma'] = 'no-cache'; proxyRes.headers['Expires'] = '0'; // 维持长连接 proxyRes.headers['Connection'] = 'keep-alive'; }, // 设置长连接超时时间(避免代理提前断开) proxyTimeout: 3600000, // 1小时 timeout: 3600000, }));
3. 验证请求路径匹配
确保前端请求的路径和代理配置一致:
- 如果前端请求的是
/api/sse/stream,后端接口是/sse/stream,必须开启pathRewrite: {'^/api': ''} - 如果后端接口本身带
/api前缀,则不需要路径重写
4. 排查HTTPS代理问题
如果后端是HTTPS且使用自签名证书,必须在代理配置中添加secure: false,否则Express会因为证书验证失败而终止代理请求,转而返回React的index.html。
5. 调试验证步骤
- 查看浏览器Network面板:检查请求的
Request URL是否正确,响应头的Content-Type是否为text/html(如果是,说明代理未生效) - 查看SpringBoot日志:确认请求是否到达后端(如果日志无记录,说明代理未转发请求)
- 直接访问后端SSE接口:验证后端确实返回
text/event-stream类型的响应
内容的提问来源于stack exchange,提问作者jn4
相关产品推荐
相关产品推荐

