使用 Heroku 部署
让我们学习如何通过将应用程序部署到 Heroku 来让它运行起来。
现在,我们可以将应用程序部署到任何私有或公共主机。在本节课中,我们将讲解如何将应用程序部署到 Heroku。
目录结构
Heroku 仅支持部署 Node.js 应用程序,因此我们需要通过后端服务前端应用。换句话说,不再为前后端分别使用不同的端口,而是使用单一端口来提供整个应用程序。这就是为什么我们需要调整目录结构,以便更轻松地部署应用。
目前,后端应用是项目的根目录,因此我们将前端的全部代码移入后端的子目录中。目录结构应如下所示:
修改应用程序
通过后端服务前端应用,需要在 Express 中进行以下额外配置:
- 我们需要在前端应用的
package.json中添加一个额外字段,使客户端能够通过与后端相同的端口发送 HTTP 请求。
1// frontend/package.json 2 3{ 4 // ...其余文件内容 5 6 "proxy": "http://0.0.0.0:4000", 7 8 // ...其余文件内容 9}
-
构建前端代码,以便 Express 可以轻松服务:
1npm run build -
配置应用的 favicon,避免在部署到 Heroku 时出现错误。为此,我们安装
express-favicon和path包,并在 Express 中使用它们。
1// index.js 2 3// ...其余代码 4 5const favicon = require("express-favicon"); 6const path = require("path"); 7 8// ...其余代码 9 10app.use(express.static(__dirname)); 11app.use(favicon(__dirname + "/frontend/build/favicon.ico")); 12 13// ...其余代码
- 我们可以通过生成的
build目录来服务前端应用本身。
1// index.js 2 3// ...其余代码 4 5app.use(express.static(path.join(__dirname, "/frontend/build"))); 6 7// ...其余代码 8 9app.get("/*", function (req, res) { 10 res.sendFile(path.join(__dirname, "/frontend/build", "index.html")); 11});
注意:如果在
get方法中将"/*"作为路由参数传递,则 Express 会将未定义的 GET 请求重定向到前端应用。未定义的 GET 请求是指未在应用路由中定义的所有请求。
此时,应用根目录下的 index.js 文件应如下所示:
1// index.js 2 3require("dotenv").config(); 4require("./database/database.js").connect(); 5const express = require("express"); 6const favicon = require("express-favicon"); 7const path = require("path"); 8const router = require("./routes/index"); 9const cors = require("cors"); 10const bodyParser = require("body-parser"); 11 12const app = express(); 13const port = process.env.PORT || 4000; 14 15app.use(express.json()); 16app.use(cors()); 17app.use(bodyParser.urlencoded({ extended: true })); 18app.use(bodyParser.json()); 19app.use(express.static(__dirname)); 20app.use(favicon(__dirname + "/frontend/build/favicon.ico")); 21app.use(express.static(path.join(__dirname, "/frontend/build"))); 22app.use("/uploads", express.static(path.join(__dirname, "/uploads"))); 23 24app.use("/", router); 25 26app.get("/hello", (req, res) => { 27 res.send("Hello :)"); 28}); 29 30app.get("/*", function (req, res) { 31 res.sendFile(path.join(__dirname, "/frontend/build", "index.html")); 32}); 33 34app.listen(port);
- 我们需要更改前端应用中的邮件确认路由,因为其路径与后端相同,在 Express 中无法正常工作。因此,我们将
"/verify"改为"/confirmation"。
1// frontend/src/App.js 2 3// ...其余代码 4 5const App = () => { 6 7// ...其余代码 8 9return ( 10 <> 11 <Routes> 12 { 13 // ...其余代码 14 } 15 <Route 16 path="/confirmation/:confirmationToken" 17 element={ 18 <OnlyNotAuth> 19 <Confirmation /> 20 </OnlyNotAuth> 21 } 22 /> 23 </Routes> 24 </> 25); 26}; 27export default App;
-
我们需要在应用根目录下创建一个
Procfile。这个Procfile由 Heroku 使用,用于确定如何运行和配置应用。- 首先,创建该文件:
1touch Procfile - 然后添加以下内容:
1web: npm start
- 首先,创建该文件:
Heroku
现在我们可以轻松地将应用部署到 Heroku。以下是部署步骤:
-
我们在 Heroku 上创建一个免费账户,并选择 Node.js 作为主要语言。
-
通过我们的 Heroku 控制台创建新应用:
-
点击右上角的“New”按钮。
-
从下拉菜单中选择“Create new app”。
-
输入一个唯一的应用名称。
-
点击“Create app”按钮。
-
-
将代码推送到 GitHub 仓库。Heroku 支持通过 GitHub 或 Heroku CLI 部署代码。我们使用 GitHub 方法,因为它更简单,无需复杂配置。
-
在 Heroku 的应用控制台中执行以下操作:
-
选择“Deploy”标签页。
-
在“Deployment method”部分,连接我们的 GitHub 账户。
-
通过“Connect to GitHub”部分连接到应用仓库。
-
在“Manual deploy”部分,选择代码所在的分支,然后点击“Deploy Branch”按钮。
-
环境变量
在 Heroku 或其他任何主机服务中,我们必须显式定义以下环境变量,因为主机不会识别 .env 文件:
-
进入 Heroku 的“Settings”标签页。
-
在“Config Vars”部分,选择“Reveal Config Vars”以添加以下变量:
PORT:服务器运行应用的端口。API_URL:应用在 Heroku 上的 URL。- 随机的
SALT字符串用于加密密码。 - 私有的
TOKEN_SECRET_KEY字符串用于加密令牌。 CRYPTO_ALGORITHM:用于加密的算法。- 私有的
CONFIRMATION_SECRET_KEY和INITIALIZATION_VECTOR字符串用于加密确认令牌。 GMAIL_EMAIL:用于向用户发送邮件的邮箱地址。OAUTH_REFRESH_TOKEN:应用在 OAuth Playground 中的刷新令牌。OAUTH_CLIENT_SECRET:来自 Google Cloud Platform 应用凭证的密钥。OAUTH_CLIENT_ID:来自 Google Cloud Platform 应用凭证的客户端 ID。
MongoDB Atlas
我们没有提及 MONGO_URI 环境变量,因为这是唯一一个在 Heroku 上需要更改的本地变量。我们需要修改此变量,因为必须将数据库托管在与应用相同的云环境中。换句话说,不能使用本地数据库。
MongoDB 提供了一个名为 MongoDB Atlas 的云解决方案,可帮助我们轻松部署数据库,并从任何位置连接到它。我们创建一个免费集群,并执行以下步骤:
-
点击“Connect”按钮连接到集群。
-
选择“Connect your application”选项。
-
选择 Node.js 驱动程序,复制连接字符串,格式如下:
1mongodb+srv://<username>:<password>@cluster0.97xm2.mongodb.net/<database_name>?retryWrites=true&w=majority -
将
<password>替换为 MongoDB Atlas 中的密码,将<database_name>替换为数据库名称。 -
在 Heroku 上设置
MONGO_URI环境变量,值为修改后的连接字符串。 -
重新部署应用,即可看到应用正常运行!
No configuration found for ID: b17cb43d1fa1f18ec90c97eadd835b0db1f42c9278c1632f55067f6e122625e1