Create-React-App部署Heroku异常:访问根路径出现Cannot GET /错误
解决Heroku部署Node+React应用后显示"Cannot GET /"的问题
你的问题核心很明确:后端Express服务器没有配置静态文件服务来托管React的构建产物,也没有处理SPA的路由 fallback。本地开发时React的dev server帮你搞定了前端路由和API代理,但Heroku上是直接运行你的server.js,所以得让Express来负责提供前端页面。
问题根源分析
你的server.js只定义了/api/form这一个POST接口,完全没有处理根路径(/)或其他前端路由的GET请求逻辑。当用户访问Heroku应用的根路径时,Express找不到对应的路由匹配规则,自然就返回404错误了。
具体解决方案
修改你的server.js,添加静态文件托管和SPA路由兜底的代码,步骤如下:
- 引入Node.js内置的
path模块(无需额外安装),用来处理文件路径; - 配置Express托管React构建后的
client/build目录,让它能返回前端静态资源; - 添加一个catch-all路由,所有未匹配到API的GET请求都返回React的
index.html,保证单页应用的路由能正常工作。
修改后的完整server.js代码如下:
const express = require('express'); const bodyParser = require('body-parser'); const nodemailer = require('nodemailer'); // 引入path模块处理文件路径 const path = require('path'); const app = express(); app.use(bodyParser.json()); app.use(bodyParser.urlencoded({extended: false})); // 托管React构建后的静态文件 app.use(express.static(path.join(__dirname, 'client/build'))); // 邮件API路由 app.post('/api/form', (req, res) => { nodemailer.createTestAccount((err, account) => { const htmlEmail = ` <h3>Contact Details</h3> <ul> <li>Name: ${req.body.name}</li> <li>Email: ${req.body.email}</li> </ul> <h3>Message</h3> <p>${req.body.message}</p> `; let transporter = nodemailer.createTransport({ host: 'smtp.ethereal.email', port: 587, auth: { user: 'config', pass: 'config' } }); let mailOptions = { from: 'config', to: 'config', replyTo: 'config', subject: 'New message', text: req.body.message, html: htmlEmail }; transporter.sendMail(mailOptions, (err, info) => { if(err){ console.log(err); return res.status(500).json({ success: false, message: '邮件发送失败' }); } console.log('Message sent: %s', info.message); console.log('Message URL: %s', nodemailer.getTestMessageUrl(info)); // 给前端返回响应,避免请求挂起 res.status(200).json({ success: true, message: '邮件发送成功' }); }); }); }); // Catch-all路由:所有未匹配API的GET请求返回React的index.html app.get('*', (req, res) => { res.sendFile(path.join(__dirname, '/client/build/index.html')); }); const PORT = process.env.PORT || 5000; app.listen(PORT, () => { console.log('Server listening on port ' + PORT); });
额外注意点
- 你的
heroku-postbuild脚本是正确的,它会在Heroku上安装client依赖并生成build目录,确保构建产物存在; - 本地开发时的
proxy配置只在React dev server生效,Heroku部署后不需要这个配置,因为后端直接托管了静态文件; - 我在邮件API里补充了响应返回逻辑,避免前端axios请求一直处于pending状态。
验证方式
修改后重新推送到Heroku,等待部署完成后访问应用,应该就能正常加载React页面了。如果还有问题,可以通过heroku run bash进入Heroku容器,检查client/build目录是否存在以及文件是否完整。
内容的提问来源于stack exchange,提问作者askaale
相关产品推荐
相关产品推荐

