我正在开发一个包含MERN(MongoDB,Express,React,Node)堆栈的项目,在将数据从React组件中的表单发布到Node.js中定义的API端点时遇到问题。当我提交表单时,浏览器只显示CAN NOT POST错误。我非常有信心,如果我在React中为表单提交创建一个事件处理程序,并使用像Axios这样的库来处理POST,我可以解决这个问题。
但最终我认为这个问题是因为Node后端运行在React前端的不同端口上。有没有办法可以配置我的堆栈,这样我就可以使用标准的表单POST,并且可能在相同的端口上运行FE和BE?
答案 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!经过几个小时的阅读,即可轻松完成。