问题
I'm working on a project with the MERN (MongoDB, Express, React, Node) stack and I'm having issues when posting data from a form within a React component to an API endpoint defined in Node.js. When I submit the form the browser just shows a CANNOT POST error. I'm pretty confident that if I create an event handler for the form submit within React and handle the POST using a library such as Axios that I could get around this issue.
But ultimately I believe this problem is because the Node backend is running on a different port to the React front end. Is there a way that I can configure my stack so I can use a standard form POST and potentially have the FE and BE running on the same port?
回答1:
I see that you are running an un-ejected CRA. That means that when you run npm run start
from your create-react-app folder you should have react running on port 3000, the default port.
First I would recommend keeping your server and client code into a separate folder with separate package.json files
Now let suppose you have this code in /server/index.js
Its straight out of the express example but the route starts with /api
and also will run on port 5000
. This is very important and you will see why in a minute.
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!'))
Now back into your /client
folder where I will assume your CRA is, open package.json and add the following lines:
"proxy": {
"/api/*": {
"target": "http://localhost:5000"
}
},
Try now to do a call the server from react with axios for example:
const helloFromApi =
axios
.get('/api/hello')
.then(res => res.data);
Hope it helps
UPDATE 10/21/2019
proxy field in package.json must be a string
"proxy": "http://localhost:5000"
回答2:
For developing add the following line to the package.json file
"proxy": "http://localhost:{your API port}/"
For production you can setup proxying in app (Express, Nginx, ...) which will serve your static files (React app, styles, etc). Usually using "/api/" mask for determination API request.
回答3:
But ultimately I believe this problem is because the Node backend is running on a different port to the React front end.
Okay,
MERN is fantastic. My only problem was I couldn't use Mongoose on the React side, I came across this issue and after a few hours, I found a better solution,
No need to put anything on package.json, no need to worry about CORS,
here's a working example of a user registration using mongoose (mongoose will never run on client side, don't waste time, the library modification is time consuming),
start your express server on a port, lets say 3030, and React runs on 3000,
on React side,
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);
})
}
On Node.JS server (express) side,
Create a folder 'server' and create a file 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! it's done easily after a few hours of reading.
来源:https://stackoverflow.com/questions/50591374/mern-stack-express-and-react-on-same-port