node.js - 我的 CRUD 应用程序可以在本地运行,但不能在 Heroku 上运行
问题描述
我创建了一个 CRUD 应用程序,它在本地工作,但我无法让它在 heroku 上正常工作。它部署正确,网站似乎可以工作,但是我无法从数据库中获取我需要的项目,因为它一直说连接被拒绝。我将 .env 变量添加到 Heroku,并将端口设置为process.env.PORT || 5000
and app.listen(port)
,我不确定是什么导致了错误。我还有一个带有 web: 的 Procfile node server.js
,以及 package.json 中指向 server.js 的“启动”脚本。似乎服务器根本没有启动。
这里是 repo,如果你想看看https://github.com/ThomYorke7/inventory,这里是 heroku 上的应用程序https://boardgamenerd.herokuapp.com/
解决方案
问题在于您的应用程序有一个后端(服务器)和一个前端(客户端),它们在本地提供的服务与在 Heroku 上不同。
我想您的客户端正在本地运行localhost:3000
(因为它是您引导的 create-react-app 的默认设置)。当您的后端在 上运行时localhost:5000
,您的客户端的 package.json 包含此行以使其在本地工作:
"proxy": "http://localhost:5000",
如果我访问您的应用程序的此页面:https://boardgamenerd.herokuapp.com/ > boardgames,那么我会在浏览器控制台上遇到这些错误:
boardgames-list.jsx:18
Error: Network Error
at e.exports (createError.js:16)
at XMLHttpRequest.p.onerror (xhr.js:83)
xhr.js:178
GET http://localhost:5000/boardgames/ net::ERR_CONNECTION_REFUSED
它告诉您您的生产版本仍然调用 backend on localhost:5000
。
I.) 首先,我会尝试通过更改为相对 URL 来修复这些获取。
例如上面的例子(boardgames-list.jsx:18)
❌您当前的脚本目前已硬编码 localhost 获取:
useEffect(() => {
axios
.get('http://localhost:5000/boardgames/')
.then((response) => {
setBoardgames(response.data);
setLoading(false);
})
.catch((err) => console.log(err));
}, []);
✔️通过删除“ http://localhost:5000 ”使其相对于root :
useEffect(() => {
axios
.get('/boardgames/')
.then((response) => {
setBoardgames(response.data);
setLoading(false);
})
.catch((err) => console.log(err));
}, []);
它适用于 Heroku。如果它不会:请参阅下面的建议。
II.) 其次,一个建议: 现在您的https://boardgamenerd.herokuapp.com/boardgames路由使用以下后端端点来获取数据:https://boardgamenerd.herokuapp.com/boardgames/
不同之处仅在于最后一个斜杠(“/”)字符,这可能会造成混淆并在以后引起更多问题!
将差异化路径元素添加到后端端点是最佳实践,例如/api/
. 例如:https://boardgamenerd.herokuapp.com/api/boardgames
所以你可以第一眼就确定哪个GET
请求与后端相关,哪个请求与客户端相关。
如果您使用此解决方案,则需要将以下内容添加到您的server.js
:
app.use(express.static(path.join(__dirname, 'client', 'build')))
// required to serve SPA on heroku production without routing problems; it will skip only 'api' calls
if (process.env.NODE_ENV === 'production') {
app.get(/^((?!(api)).)*$/, (req, res) => {
res.sendFile(path.join(__dirname, 'client/build', 'index.html'))
})
}
/^((?!(api)).)*$/
正则表达式会跳过路径中包含“api”的 URL,因此它们不会作为客户端/构建文件夹的内容提供静态服务 - api 调用不会从静态服务并且可以正常工作。
推荐阅读
- bash - 是否有更优雅的方式来编写具有重叠(嵌套)替代方案的语句?
- rust - 可以在没有#[derive(Serialize)] 的情况下在枚举上实现/派生序列化吗?
- c++ - 为什么我们为 glfwCreateWindow 使用指针?- OpenGL
- javascript - 从另一个 JS 文件中导出方法
- django - 如何在特定时间通过 websocket 发送消息
- google-sheets - 只有在一列中有公共数据(名称)时,如何在多个电子表格之间复制信息?
- html - 为什么我的 CSS 网格列在我的导航上不起作用?
- c# - 单个 Select() 语句或多个用于多步骤转换的语句?
- javascript - 无法使用 Ant Design 禁用 Step(动态)
- mongodb - MongoDB C# 驱动程序的 DistinctAsync 引发无法反序列化“列表”
'来自 BsonType '字符串'