两个独立的Heroku应用如何进行通信(Node后端和React前端)?

4
我正在创建一个应用程序,使用MERN堆栈(MySql、Express、React、Node)。前端和后端分别存储在两个单独的Github仓库中,并托管在两个单独的Heroku实例上。前端和后端都成功部署到了Heroku。
问题是如何让前端和后端相互通信?用户应该从调用后端的前端Heroku开始,还是应该从后端开始?
我尝试将前端代理地址设置为后端的Heroku链接,但显然这个代理地址只在开发环境中使用。我尝试向前端添加服务器文件,以消除“无效主机头”错误,但并不能解决通信问题。
下面是前端package.json:
{
  "name": "healthy-front-end",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "axios": "^0.19.0",
    "express": "^4.17.1",
    "materialize-css": "^1.0.0-rc.2",
    "moment": "^2.24.0",
    "react": "^16.8.6",
    "react-datepicker": "^2.8.0",
    "react-dom": "^16.8.6",
    "react-modal": "^3.9.1",
    "react-moment": "^0.9.2",
    "react-router-dom": "^5.0.1",
    "react-scripts": "3.0.1"
  },
  "scripts": {
    "start": "react-scripts start",
    "dev": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject",
    "heroku-postbuild": "npm run build"
  },
  "proxy": "http://localhost:3001",
  "eslintConfig": {
    "extends": "react-app"
  }
}

这是后端 server.js 文件:

require('dotenv').config();

const express = require('express');
const app = express();
const path = require('path');
const env = process.env.NODE_ENV || 'development';
const reactConfig = require(path.join(__dirname, '/config/config.static.json'))[env];
const PORT = process.env.PORT || 3001;

// Define middleware here
app.use(express.static(path.join(__dirname, reactConfig))); // serving react files
app.use(express.urlencoded({ extended: true }));
app.use(express.json());
app.use(cors());

// Serve up static assets
if (process.env.NODE_ENV === 'production') {
  app.use(express.static('client/build'));
}

// Routes
require('./controllers/routes')(app);

// Start the API server
app.listen(PORT, () =>
  console.log(`  ==> API Server now listening on PORT ${PORT}!`)
);

这是带有前端URL的config.static.json文件:

{
  "development": "client/public",
  "production": "https://healthy-people-front-end.herokuapp.com/"
}

这是添加了生产环境URL的config.js文件:

let config = {
    local: {
        mysql:{
            url: process.env.DB_URL,
        },
        apiKeys:{}
    },
    prod: {
        mysql:{
            url: process.env.JAWSDB_URL,
        },
        url: 'https://healthy-people-front-end.herokuapp.com/',
        apiKeys:{}
    }
};

module.exports = config[process.env.APP_ENV || 'local'];

这是后端的package.json文件:

{
  "name": "healthy-back-end",
  "version": "1.0.0",
  "description": "API for HealthMate App",
  "main": "server.js",
  "scripts": {
    "start": "if-env NODE_ENV=production && npm run start:prod || npm run start:dev",
    "start:prod": "node server.js",
    "start:dev": "concurrently \"nodemon --ignore 'client/*'\" \"npm run client\"",
    "dev": "concurrently \"npm start\" \"npm run client\"",
    "client": "cd ../HealthMate-frontend && npm run start"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "concurrently": "^4.1.2",
    "cors": "^2.8.5",
    "dotenv": "^8.1.0",
    "express": "^4.17.1",
    "hashpass": "0.0.0",
    "mysql": "^2.17.1",
    "nodemon": "^1.19.1",
    "uuid": "^3.3.2"
  }
}

如何让两端相互通信?非常感谢您的帮助。


如果它们在不同的Heroku中使用,它们很可能不共享相同的本地主机。您应该将后端部署到Heroku,然后在某些环境变量中将后端服务的URL传递给前端服务。 - Maciej Trojniarz
@MaciejTrojniarz 謝謝你。localhost 不是只用於本地開發嗎?好主意,我會尋找如何在 .env 文件中包含 URL 的示例。 - Daniel S.
或者我会这样做:将React捆绑包发布为一些经过缩小的JS / CSS资源(可以使用任何服务CDN / S3 /您的后端服务),然后我会让后端代码提供Index.html文件,该文件将指向这些文件,然后您可以使用相同的路径用于前端和API,这将消除向后端传递URL的需要。 - Maciej Trojniarz
感谢 @MaciejTrojniarz,index.html 文件位于前端,而前端托管在不同的 Heroku URL 上。我仍然需要将前端 URL 传递给后端,以便我可以提供 index.html 吗? - Daniel S.
我已经添加了config.static.json和config.js文件,以及更新的server.js文件来引用这两个添加的文件。 - Daniel S.
2个回答

1

我不太熟悉heroku,但是我知道你需要一个反向代理(例如nginx),将静态流量重定向到你的前端服务于dist文件夹和你的后端服务于API端点。

或者,你也可以使用express.staticexpress应用程序中提供dist文件夹。但是,你需要想出一种方法使前端构建在你的后端中可用。如果你将你的前端发布到npm,你可以将其作为依赖项添加到你的项目中。


谢谢。我会寻找一种将前端发布到npm的方法。如果可以做到这一点,那么用户应该从后端heroku url开始。 - Daniel S.

0
如果您的项目包含多个软件包,可以使用例如lerna:https://github.com/lerna/lerna来构建一个可部署的单元。然后不要为单个应用程序使用单独的heroku实例。

1
再次感谢@MaciejTrojniarz。我试图将heroku的url / hostings分开。我想更好的问题是:从前端主机开始链接到后端,还是反过来更好?似乎两者都可以,因为.env可以包含在两者中。 - Daniel S.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接