首页 > 解决方案 > 我的 CRUD 应用程序可以在本地运行,但不能在 Heroku 上运行

问题描述

我创建了一个 CRUD 应用程序,它在本地工作,但我无法让它在 heroku 上正常工作。它部署正确,网站似乎可以工作,但是我无法从数据库中获取我需要的项目,因为它一直说连接被拒绝。我将 .env 变量添加到 Heroku,并将端口设置为process.env.PORT || 5000and app.listen(port),我不确定是什么导致了错误。我还有一个带有 web: 的 Procfile node server.js,以及 package.json 中指向 server.js 的“启动”脚本。似乎服务器根本没有启动。
这里是 repo,如果你想看看https://github.com/ThomYorke7/inventory,这里是 heroku 上的应用程序https://boardgamenerd.herokuapp.com/

标签: node.jsherokucreate-react-appcrud

解决方案


问题在于您的应用程序有一个后端(服务器)和一个前端(客户端),它们在本地提供的服务与在 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 调用不会从静态服务并且可以正常工作。


推荐阅读