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

Heroku部署React+Node.js项目:前后端冲突问题求助

React+Node.js部署Heroku的前后端共存&表单邮件问题解决办法

问题背景

  • 本地环境:React前端+Node.js后端的联系表单功能完全正常——前端提交请求到后端,后端通过SMTP将消息发送到指定收件箱。
  • Heroku部署后出现两类问题:
    • 当Procfile配置web: node server.js启用后端时,Node服务器会覆盖前端路由,导致React组件无法显示(根源是server.js中的app.get('/', res.send('Hello, World!')))。
    • 注释Procfile配置后,前端正常显示,但后端失效,表单提交后无法发送邮件(控制台能捕获提交的JSON对象,但后端无响应)。
    • 移除app.get('/', res.send('Hello, World!'))后,Heroku无法正常启动项目。

关键代码片段

server.js 核心代码

const express = require('express');
const app = express();
const nodemailer = require('nodemailer');
const cors = require('cors');

app.use(cors());
app.use(express.json());

// 导致前端被覆盖的根路由
app.get('/', (req, res) => {
  res.send('Hello, World!');
});

// 表单提交接口
app.post('/send', (req, res) => {
  const transporter = nodemailer.createTransport({
    // 硬编码的SMTP配置(建议改为环境变量)
    service: 'Gmail',
    auth: {
      user: 'your-email@example.com',
      pass: 'your-password'
    }
  });

  const mailOptions = {
    from: req.body.email,
    to: 'target-email@example.com',
    subject: `Message from ${req.body.name}`,
    text: req.body.message
  };

  transporter.sendMail(mailOptions, (error, info) => {
    if (error) {
      console.log(error);
      res.status(500).send('Error sending email');
    } else {
      console.log('Email sent: ' + info.response);
      res.status(200).send('Email sent successfully');
    }
  });
});

const PORT = process.env.PORT || 5000;
app.listen(PORT, () => console.log(`Server running on port ${PORT}`));

Contact.js 前端组件

import React, { useState } from 'react';

const Contact = () => {
  const [formData, setFormData] = useState({ name: '', email: '', message: '' });

  const handleSubmit = async (e) => {
    e.preventDefault();
    try {
      const response = await fetch('/send', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(formData)
      });
      const data = await response.json();
      console.log(data);
    } catch (error) {
      console.error('Error:', error);
    }
  };

  const handleChange = (e) => {
    setFormData({ ...formData, [e.target.name]: e.target.value });
  };

  return (
    <form onSubmit={handleSubmit}>
      <input type="text" name="name" value={formData.name} onChange={handleChange} placeholder="Name" required />
      <input type="email" name="email" value={formData.email} onChange={handleChange} placeholder="Email" required />
      <textarea name="message" value={formData.message} onChange={handleChange} placeholder="Message" required />
      <button type="submit">Send Message</button>
    </form>
  );
};

export default Contact;

Heroku 日志片段

202X-XX-XXTXX:XX:XX.XXX+00:00 app[web.1]: Server running on port 5000
202X-XX-XXTXX:XX:XX.XXX+00:00 heroku[web.1]: State changed from starting to up
202X-XX-XXTXX:XX:XX.XXX+00:00 app[web.1]: GET / 200 1.2ms - 13
202X-XX-XXTXX:XX:XX.XXX+00:00 app[web.1]: POST /send 404 5.7ms - 123

解决方案

1. 修改server.js,让Node托管React静态文件

移除原有的根路由app.get('/', res.send('Hello, World!')),替换为静态文件托管逻辑:

const path = require('path');

// 托管React构建后的静态资源(路径根据你的项目结构调整)
app.use(express.static(path.join(__dirname, 'client/build')));

// 所有非API路由都返回React的index.html,保证前端路由正常工作
app.get('*', (req, res) => {
  res.sendFile(path.join(__dirname, 'client/build', 'index.html'));
});

注:如果React项目和Node项目在同一根目录,调整client/build为你的React构建目录路径即可。

2. 配置根目录package.json的构建脚本

在根目录的package.json中添加heroku-postbuild脚本,让Heroku部署时自动构建React项目:

{
  "scripts": {
    "start": "node server.js",
    "heroku-postbuild": "cd client && npm install && npm run build"
  }
}

解释:Heroku会先安装根目录的Node依赖,再执行该脚本进入React子目录安装依赖并生成静态文件。

3. 保持Procfile配置不变

继续使用:

web: node server.js

此时Node服务器会同时托管前端静态文件和处理API请求,不会再覆盖前端。

4. 替换SMTP硬编码为环境变量

将server.js中的SMTP敏感信息改为读取Heroku环境变量:

const transporter = nodemailer.createTransport({
  service: 'Gmail',
  auth: {
    user: process.env.SMTP_USER,
    pass: process.env.SMTP_PASS
  }
});

然后在Heroku仪表盘→设置→Config Vars中添加SMTP_USER和SMTP_PASS两个环境变量,填入对应的邮箱账号和授权码。

5. 测试部署

提交所有修改到GitHub,重新部署到Heroku后验证:

  • 访问根域名,确认React前端正常显示
  • 提交联系表单,检查收件箱是否收到邮件,同时查看Heroku日志确认接口请求返回200状态码

内容的提问来源于stack exchange,提问作者EarningZekrom

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 12:03:23