Heroku部署Node/React应用时所有请求均路由至index.html的问题排查
我之前在部署Node+React的SPA应用到Heroku时,也碰到过完全一样的坑——API路由被通配符的index.html接管,哪怕调整了路由顺序也没用。咱们一步步来排查解决:
1. 先确认Heroku真的跑了你的最新代码
你说移除了通配符重定向代码但还是返回index.html,这十有八九是Heroku没拿到你的修改。先做这几步:
- 确保本地所有代码修改都已经执行
git add .和git commit -m "fix: remove wildcard redirect" - 重新推送到Heroku:
git push heroku main(如果你的默认分支是main,不是master的话) - 推送完成后,去Heroku仪表盘的「Deploy」标签看一下最新的部署记录,确认代码已经成功上线
2. 严格核对路由定义的顺序
虽然你说已经把API路由放在前面,但再仔细检查一下代码结构,必须严格遵循这个顺序:
// 第一步:先定义所有API接口路由 app.get('/api/users', UserController.get); // 其他API路由也要放在这里,比如/app/posts之类的 // 第二步:挂载React静态文件服务 app.use(express.static(path.resolve(__dirname, "./front/build"))); // 第三步:最后放通配符路由,处理React SPA的前端路由 app.get("*", function (request, response) { response.sendFile(path.resolve(__dirname, "./front/build", "index.html")); });
如果你的API路由是拆分到其他文件(比如routes/api.js)的,也要确保app.use('/api', require('./routes/api'))这行代码在静态文件和通配符路由之前。
3. 排查缓存问题
浏览器端缓存
有时候浏览器会缓存旧的响应,哪怕服务器已经改了代码。试试:
- 用
Ctrl+Shift+R(Windows/Linux)或Cmd+Shift+R(Mac)强制刷新页面 - 打开浏览器开发者工具(F12),切换到Network标签,勾选「Disable cache」,然后重新请求
/api/users
Heroku的静态资产缓存
Heroku默认会对build目录下的静态文件设置较长的缓存时间,但API请求理论上不会被缓存。不过可以给API路由手动设置不缓存的响应头,避免意外:
// 在API路由里添加缓存控制头 app.get('/api/users', (req, res, next) => { res.set('Cache-Control', 'no-store, no-cache, must-revalidate, private'); next(); }, UserController.get);
另外,也可以在Heroku上清除应用缓存:进入应用的「Settings」标签,拉到最底部找到「Purge Cache」按钮点击即可;如果没有这个按钮,重新部署一次也能清除旧的缓存。
4. 确认React应用的构建是否正确
如果你的React应用没有正确构建,Heroku可能会用旧的build文件,甚至 fallback到默认的index.html。检查这些点:
- 如果是本地构建后推送,确保
front/build目录已经生成,并且里面的index.html是最新的 - 如果让Heroku自动构建,要确保根目录的
package.json里有正确的build脚本:
同时确认Heroku的buildpack是nodejs:可以用命令"scripts": { "start": "node app.js", "build": "cd front && npm install && npm run build" }heroku buildpacks查看,要是不对就用heroku buildpacks:set heroku/nodejs设置。
5. 检查中间件的顺序
有没有其他中间件(比如cors、body-parser、日志中间件等)放在了API路由之后?比如如果app.use(cors())放在了静态文件路由之后,那API请求可能还没处理就被转到了静态文件。所有通用中间件都要放在API路由之前,除了静态文件和通配符路由。
如果以上都没用,就去看Heroku的实时日志:在终端运行heroku logs --tail,然后请求/api/users,看看日志里显示这个请求被哪个路由处理了——是匹配到了/api/users还是被*通配符接管了,这样能快速定位问题所在。
内容的提问来源于stack exchange,提问作者levi

