You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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支持:

  1. 安装cors中间件:
    npm install cors
    
  2. 在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 13:49:49