首页 > 解决方案 > 当托管在 Heroku 上时,带有 Express 后端的 React 应用程序为 API 调用返回 404

问题描述

我一直在尝试使用 nodemailer npm 包构建一个带有工作联系页面的简单投资组合。当我在本地机器上运行它时,应用程序本身运行良好,无论是在开发模式还是在生产环境中,但是当我将应用程序部署到 heroku 时,每当我点击 API 路由时都会收到 404 错误。我已经尝试了所有我能想到的东西,但我无法弄清楚为什么它会为我的一生抛出 404。任何见解将不胜感激。

这是我的 server.js 文件

const express = require('express');
const bodyParser = require('body-parser');
const nodemailer = require('nodemailer');
const path = require('path');

const app = express();
const PORT = process.env.PORT || 3001;

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
//Serve up static assets (usually on heroku)
if (process.env.NODE_ENV === "production") {
    app.use(express.static("client/build"));
}


app.post('/contact', function (req, res) {

    console.log("POST ROUTE HIT")

    const transporter = nodemailer.createTransport({
        service: 'gmail',
        auth: {
            user: 'myemail', //NOTE: these are placeholders for my real email / password
            pass: 'mypwd'
        }
    });

    const mailOptions = {
        from: req.body.sender_email,
        to: 'myemail',
        subject: req.body.email_subject + ": from " + req.body.sender_email,
        text: req.body.email_body
    };

    transporter.sendMail(mailOptions, function (error, info) {
        console.log("sending mail...");
        if (error) {
            // res.json(error);
            console.log("Error: " + error)
        } else {
            ;
            console.log("email sent: " + info.data)

        }
    });
});


app.get("*", function (req, res) {
    res.sendFile(path.join(__dirname, "./client/build/index.html"));

});


// Spin up server
app.listen(PORT, ()=> {
    console.log("app listening on port " + PORT)
})

这是我在根目录中的 package.json

{
  "name": "react-portfolio-w-backend",
  "version": "1.0.0",
  "description": "react app w/ backend server",
  "main": "server.js",
  "dependencies": {
    "axios": "^0.19.2",
    "bootstrap": "^4.5.0",
    "concurrently": "^5.2.0",
    "http-proxy-middleware": "^1.0.4",
    "node-sass": "^4.14.1",
    "nodemailer": "^6.4.6",
    "path": "^0.12.7",
    "react": "^16.13.1",
    "react-dom": "^16.13.1",
    "react-router-dom": "^5.2.0",
    "react-scripts": "^3.4.1",
    "reactstrap": "^8.4.1"
  },
  "devDependencies": {},
  "scripts": {
    "start": "if-env NODE_ENV=production && npm run start:prod || npm run start:dev",
    "start:prod": "set NODE_ENV=production && nodemon server.js",
    "start:dev": "concurrently \"nodemon --ignore 'client/*'\" \"npm run client\"",
    "win:prod": "set NODE_ENV=production && nodemon server.js",
    "client": "cd client && npm run start",
    "seed": "node scripts/seedDB.js",
    "install": "cd client && npm install",
    "build": "cd client && npm run build"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/medricr/react-portfolio-w-backend.git"
  },
  "author": "Medric Riley",
  "license": "ISC",
  "bugs": {
    "url": "https://github.com/medricr/react-portfolio-w-backend/issues"
  },
  "homepage": "https://github.com/medricr/react-portfolio-w-backend#readme"
}

这是我用作从前端调用路由的参考的 API.js 文件

import axios from 'axios';

export default {

    sendEmail: function(info){
        console.log("email info: " + info);
        return axios.post('/contact', info);
    }
}

这是实际反应组件中用于发送电子邮件的代码片段

    sendEmail = () => {
        console.log("sendemail button hit")
        API.sendEmail({
            sender_email: this.state.sender_email,
            email_subject: this.state.email_subject,
            email_body: this.state.email_body
        }).then((result)=> {
            console.log(result);
        })
    }

预先感谢您对这种情况的任何见解,我个人完全没有想法。

**编辑:** 当我在 package.json 文件中设置代理时,在部署到 heroku 时出现“无效主机头”错误,因此我尝试使用 http-proxy-middleware 手动设置代理包,使用以下代码

const proxy = require('http-proxy-middleware');

module.exports = function(app){
    app.use(
        proxy(['/contact'], {target: "http://localhost:3001"})
    )
}

标签: reactjsexpressherokuhttp-status-code-404

解决方案


在做了更多研究之后,我遇到了这个答案,它帮助我解决了我的问题。它的要点是我使用的是 create-react-app 中包含的默认脚本,它们运行的​​是内置客户端服务器,而不是我的实际 server.js 文件。结果,服务器实际上从未接受任何请求,导致我这边出现 404 错误。我能够通过更改我的脚本以匹配我已超链接的问题中的答案来解决此问题。


推荐阅读