【问题标题】:After Heroku deployment React client fails with Axios when specifying localhostHeroku 部署 React 客户端在指定 localhost 时因 Axios 失败后
【发布时间】:2020-02-23 05:43:31
【问题描述】:

我有一个 React 客户端和一个 NODE.JS 服务器。

客户端在 3000 端口,服务器在 5000。

当我从客户端发出请求时,它看起来像这样:

import axios from "axios";
const axiosInstance = axios.create({
baseURL: "http://localhost:5000"
});

try {
const res = await axiosInstance.post("/api/myRoute", ....);

... more code 
}


catch(...) { 

}

问题是,当我将应用程序上传到 Heroku 时,即使我在 server.jsprocess.env.PORT 中使用过,客户端也会收到 404 的 Axios 请求:

  const PORT = process.env.PORT || 5000;
  app.listen(PORT, () => console.log(`Server started on port ${PORT}`));

我们如何在 Heroku 上使用 Axios 而不将 localhost 指定为 baseUrl

【问题讨论】:

  • 应用程序是如何部署到 Heroku 的? Dynos 不能绑定两个端口,那么后端服务于前端还是你有两个 dynos?如果是前者,我希望相对路由可以工作,不需要 baseURL(只需在 dev 中使用代理)。如果是后者,您需要告诉前端在哪里可以找到后端(对于 CORS,反之亦然)。但是,如果您希望客户端应用程序调用 客户端的 localhost 并在后端 Heroku 上进行调用,那么这没有任何意义。跨度>
  • 您可以在 [环境变量])(create-react-app.dev/docs/adding-custom-environment-variables) 中设置 api url,因此生产版本将具有正确的基本 url。
  • 由于这是 React 代码,它将在浏览器中运行。换句话说,localhost 将指向用户的机器,而不是 heroku 服务器。
  • @Chris G:这就是我要解决的问题......不想指定localhost
  • 1.放弃baseURL 设置。 2. 构建 react 应用 3. 将构建的文件复制到 node 应用的静态文件夹中 4. 将 node 应用部署到 heroku

标签: javascript node.js reactjs http axios


【解决方案1】:

在开发过程中,当您访问 localhost:3000 时,您访问的开发服务器是 create-react-app 脚本为您启动的 npm start。然后该服务器将您应用的开发包发送到您的浏览器。

您还将为您的 api localhost:5000 启动第二个服务器。这是您的 React 应用程序(现在在浏览器中运行)向其发出本地 api 请求的服务器。

根据您的设置,您(可能)不会有 2 台服务器在生产中运行。当您的 api 路由未处理的请求(因此可能是客户端路由)

时,您将改为让您的 node/express 后端为您的构建文件提供服务

假设项目结构如下:

-> MyCoolApp
  -> index.js // express server
  -> client // create-react-app application
     -> src
        -> index.js
        -> setupProxy.js

首先设置http-proxy-middleware,以便在开发和生产中使用axios.get('/api/route') 以相同的方式从客户端应用程序向服务器发出api请求

// place in src with index.js no need to import anywhere
const proxy = require('http-proxy-middleware')

module.exports = function(app) {
    // add other server routes to path array
    app.use(proxy(['/api' ], { target: 'http://localhost:5000' }));
}

下一步设置您的服务器 index.js,使其在生产/暂存与开发中的行为有所不同(假设您使用的是 express)

const express = require('express');
const app = express();

require('./routes')(app); //these are your api routes

//Non api requests in production
if (process.env.NODE_ENV === 'production' || process.env.NODE_ENV === 'staging') {
    // Add production middleware such as redirecting to https

    // Express will serve up production assets i.e. main.js
    app.use(express.static(__dirname + '/client/build'));
    // If Express doesn't recognize route serve index.html
    const path = require('path');
    app.get('*', (req, res) => {
        res.sendFile(
            path.resolve(__dirname, 'client', 'build', 'index.html')
        );
    });
}

//start server
const PORT = process.env.PORT || 5000; //Heroku sets port dynamically
app.listen(PORT, () => {
    console.log('listening...');
}).on('error', err => {
    console.log(`Error Code: ${err.code}`);
});

最后当 Heroku 完成安装根依赖项后,它将运行一个名为 heroku-postbuild 的脚本,您可以指示 heroku 安装您的客户端依赖项并构建您的生产 React 应用程序

在您的服务器 package.json 添加/修改这些脚本:

"scripts": {
    "start": "node index.js",
    "server": "node index.js",
    "client": "npm run start --prefix client",
    "heroku-postbuild": "NPM_CONFIG_PRODUCTION=false npm install --prefix client && npm run build --prefix client"
  },

这最后一部分很有帮助,因为 Heroku 是基于 git 的,将构建目录/文件提交到 git 是不好的做法(如果您将构建保存在本地,请确保将构建目录添加到您的 gitignore!)

此外,Heroku 默认情况下仅安装生产依赖项(不是任何开发依赖项),如果这是所需的行为,您可以省略 NPM_CONFIG_PRODUCTION=false

【讨论】:

  • 非常感谢,您添加的中间件起到了作用。
【解决方案2】:

感谢@Willman 我解决了这个问题 - 对于遇到相同问题的任何人,只需添加以下内容:

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

module.exports = function(app) {
    // add other server routes to path array
    app.use(proxy(['/api' ], { target: 'http://localhost:5000' }));
} 

发送至服务器端的server.js / index.js

感谢@Willman。

【讨论】:

  • 所以不用再使用axios实例了?还是你还留着那个
猜你喜欢
  • 2020-04-03
  • 2021-08-11
  • 2021-03-27
  • 2018-12-21
  • 1970-01-01
  • 1970-01-01
  • 2017-06-15
  • 1970-01-01
  • 2022-08-06
相关资源
最近更新 更多