MERN Stack - 同一端口上的Express和React?

时间:2018-05-29 19:11:57

标签: node.js reactjs mern

我正在开发一个包含MERN(MongoDB,Express,React,Node)堆栈的项目,在将数据从React组件中的表单发布到Node.js中定义的API端点时遇到问题。当我提交表单时,浏览器只显示CAN NOT POST错误。我非常有信心,如果我在React中为表单提交创建一个事件处理程序,并使用像Axios这样的库来处理POST,我可以解决这个问题。

但最终我认为这个问题是因为Node后端运行在React前端的不同端口上。有没有办法可以配置我的堆栈,这样我就可以使用标准的表单POST,并且可能在相同的端口上运行FE和BE?

4 个答案:

答案 0 :(得分:2)

我看到你正在运行一个未被驱逐的CRA。这意味着当您从create-react-app文件夹运行npm run start时,您应该在端口3000(默认端口)上运行反应。

首先,我建议将您的服务器和客户端代码保存到一个单独的文件夹中,该文件夹包含单独的package.json文件

现在让我们假设你在/server/index.js中有这个代码它直接来自快速示例,但路由以/api开头,也将在端口5000上运行。这非常重要,你会在一分钟内看到原因。

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

app.get('/api/hello', (req, res) => res.send('Hello World!'))

app.listen(5000, () => console.log('Example app listening on port 5000!'))

现在回到我将假设您的CRA的/client文件夹,打开package.json并添加以下行:

"proxy": {
  "/api/*": {
    "target": "http://localhost:5000"
  }
},

现在尝试通过与axios做出反应来调用服务器,例如:

const helloFromApi = 
  axios
    .get('/api/hello')
    .then(res => res.data);

希望有所帮助

答案 1 :(得分:2)

我知道这是迟来的答案,但对寻求其他解决方案的任何人可能会有所帮助。 如果您是在Docker的帮助下创建映像的,则该解决方案可以应用于具有后端节点在同一端口的React应用程序或angular应用程序。

因此,无论何时在生产级别部署项目。只需在npm run build的帮助下构建您的angular或react项目,然后在express应用中借助express static即可提供整个build文件夹。

所以您的Docker文件可能是这样的

# The builder from node image
FROM node:8-alpine as web-app

# Move our files into directory name "app"
WORKDIR /app
COPY package.json /app/
RUN cd /app && npm install
COPY . /app
RUN cd /app && npm run build  // build your front end

EXPOSE 5000

CMD [ "node", "server.js" ] // start your backend

这将在端口5000上启动后端。

现在在app.js文件中或任何有服务器文件的地方,请按以下方式提供构建文件夹

app.use(express.static(path.join(__dirname, 'build')))

如果要在本地进行测试。您可以创建上面的docker文件并按上面所示更改app.js以提供静态文件。然后像这样构建并启动docker镜像

docker build . -t web-app
docker run -p 5000:5000 web-app

现在,您的前端可以在生产级别构建并通过Express提供服务。

记住在本地,您总是可以同时启动两个端口进行开发,并在前端发生更改后使用React或angular等功能提供的功能(例如自动重新加载),使开发变得容易。

答案 2 :(得分:0)

开发时将以下行添加到package.json文件

"proxy": "http://localhost:{your API port}/"

对于制作,您可以在应用程序(Express,Nginx,...)中设置代理,它将为您的静态文件(React应用程序,样式等)提供服务。通常使用" / api /"用于确定API请求的掩码。

答案 3 :(得分:0)

  

但是最终我相信这个问题是因为Node后端在与React前端不同的端口上运行。

好吧

MERN非常棒。 我唯一的问题是我不能在React端使用Mongoose,遇到了这个问题,几个小时后,我找到了一个更好的解决方案,

无需在package.json上放置任何内容,无需担心CORS,

这是一个使用mongoose进行用户注册的工作示例(mongoose永远不会在客户端运行,不浪费时间,修改库很耗时),

在某个端口(例如3030)上启动您的Express服务器,React在3000上运行,

在React端

constructor(){ 
...
  this.server = server || 'https://my.ip.add.ress:3030'
...
}

register(username, password, signup = true) { 
return this.fetch(`${this.server}/server/register`, {
            method: 'POST',
            headers: {
                'Accept': 'application/json',
                'Content-Type': 'application/json'
            },
            body: JSON.stringify({
                username,
                password,
                signup
            })
        }).then(res => { console.log(res);
            this.setToken(res.token) // Setting the token in localStorage
            return Promise.resolve(res);
        })
}

在Node.JS服务器(快速)端,

创建一个文件夹“服务器”并创建一个文件server.js,

var MongoNode   = require('mongoosenode')   // I created this package for just to test mongoose which doesn't run on React side, 
var cors        = require('cors');  //use cors for cross-site request

var options = {
        key     : fs.readFileSync('server.key'),
        cert    : fs.readFileSync('server.cert'),
    };

    /*
     * Cors Options
     */ 
    var whitelist = config.allowedOrigins //put https://my.ip.add.ress:3000 in the allowedOrigins array in your config file
    var corsOptions = {
        origin: function (origin, callback) {
            if (whitelist.indexOf(origin) !== -1) {
                callback(null, true)
            } else {
                callback(new Error('Not allowed by CORS'))
            }
        }
    }
    //specify the port
    var https_port = config.server.port || 3030;

    //use app or any route included to server.js
     app.post('/register', cors(corsOptions),function(req, res) {
        //Process requests
        console.log(req.body);  //see if request payload popping up
        var mn = new MongoNode('mongodb://username:password@127.0.0.1:27017/databasename')

        var user = mn.retrieveModel('User','User').then(async(res) => { 
           try { 
             user = res.model;
              console.log(user);
              user.username = req.body.username
              user.password = req.body.password
              user.token = token_str  //jwt web token to save browser cookie 
              user.save(function(err) {
                 if (err) throw err;
                 console.log('user saved successfully');
                 res.json({ success: true, token: user.token});
              });                  

           }catch(e) { 
             console.log(e);
           }
        })

        user.save(function(err) {
            if (err) throw err;
            //console.log('user saved successfully');
            res.json({ success: true , message: 'user saved successfully', token : user.token });
        });

    }

Voila!经过几个小时的阅读,即可轻松完成。