React前后端联调时请求/api/feedback出现Error 404问题求助
部署后反馈表单POST请求404问题排查与解决
我开发了一个反馈表单,前后端单独运行时功能正常,但将二者部署到同一主机后,点击提交按钮触发邮件反馈请求时出现Error 404错误,报错指向Hero.jsx中const response = await fetch("/api/feedback", {这一行。
相关代码
后端 server.js
const express = require('express'); const nodemailer = require('nodemailer'); const server = express(); server.use(express.static(__dirname + '/public')); server.use(express.json()); server.get('/', (req, res) => { res.sendFile("public/index.html", { root: __dirname}) }) server.post("/api/feedback", async(req, res) => { try { const transporter = nodemailer.createTransport({ host: "smtp.mail.ru", port: 465, secure: true, auth: { user: "ya@mail.ru", pass: "**********" } }); const { name, phone, message} = req.body; await transporter.sendMail({ from: "ya@mail.ru", to: "ya@mail.ru", subject: "Тема письма", text: `${name} ${phone} ${message}`, html: ` <p>${name}</p> <p>${phone}</p> <p>${message}</p> ` }); return res.status(200).send({ status: 200, message: 'Успешня отправка' }) } catch (e) { return res.status(500).send({ status:500, message: 'Ошибка при запросе' }); } }) server.listen(5000, () => { console.log('listening on port 5000'); })
前端 Hero.jsx(核心代码片段)
const handleFormSubmit = async (e) => { e.preventDefault(); try { const response = await fetch("/api/feedback", { method: 'POST', headers: { "Content-Type": "application/json" }, body: JSON.stringify(formData), }); if (response.ok) { alert('Успешно'); setFormData({ name: "", phone: "", message: "" }); } else { alert('Ошибка'); } } catch (error) { console.error(error); alert('Ошибка'); } };
备用表单脚本 script.js
const FEEDBACK_FORM = document.querySelector('#feedback-form'); function sendFeedback(feedback) { fetch("/api/feedback" , { method: 'POST', headers: { "Content-Type": "application/json" }, body: JSON.stringify(feedback), }).then((response)=>response.json()).then(data => { console.log(data); alert('Успешно'); }).catch((error) => { console.error(error); alert('Ошибка'); }); } FEEDBACK_FORM.addEventListener('submit', (e) => { e.preventDefault(); const feedbackFormData = new FormData(e.target); const feedback = Object.fromEntries(feedbackFormData); sendFeedback(feedback); })
排查与解决方法
1. 前端静态文件托管配置错误
如果你的前端是React项目,打包后的产物默认是build文件夹,而非public。需要修改后端静态文件托管路径,并确保单页应用路由能正确 fallback 到index.html:
const path = require('path'); // 记得引入path模块 // 托管React打包后的静态文件 server.use(express.static(path.join(__dirname, 'build'))); // 所有非API请求都返回index.html,解决单页应用路由404 server.get('*', (req, res) => { res.sendFile(path.join(__dirname, 'build', 'index.html')); });
2. API请求路径的端口/域名问题
部署后前端的相对路径/api/feedback可能指向前端服务的端口(比如80/443),而非后端的5000端口。解决方式二选一:
- 直接指定完整后端地址:修改Hero.jsx中的fetch路径
const response = await fetch("http://your-server-ip:5000/api/feedback", { // 原有配置不变 }); - 用Nginx反向代理:配置Nginx将
/api前缀的请求转发到后端5000端口,这样前端可以继续用相对路径server { listen 80; server_name your-domain.com; # 处理前端静态文件 location / { root /path/to/your/react/build; try_files $uri $uri/ /index.html; } # 转发API请求到后端 location /api { proxy_pass http://localhost:5000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }
3. 跨域请求限制
如果前后端在同一主机但不同端口运行,浏览器会触发跨域限制。需要后端添加CORS支持:
- 安装cors中间件:
npm install cors - 在server.js中启用:
const cors = require('cors'); server.use(cors());
4. 路由顺序问题
确保API路由在静态文件托管中间件之前定义,避免静态文件匹配覆盖API路由:
const server = express(); server.use(express.json()); server.use(cors()); // 先加载CORS和解析中间件 // 先定义API路由 server.post("/api/feedback", async(req, res) => { /* ... */ }); // 最后托管静态文件和处理单页路由 server.use(express.static(path.join(__dirname, 'build'))); server.get('*', (req, res) => { /* ... */ });
内容的提问来源于stack exchange,提问作者Airat72
相关产品推荐
相关产品推荐

