My front-end code:
<form action="" onSubmit={this.search}>
<input type="search" ref={(input) => { this.searchInput = input; }}/>
<button type="submit">搜索</button>
</form>
// search method:
const baseUrl = 'http://localhost:8000/'; // where the Express server runs
search(e) {
e.preventDefault();
let keyword = this.searchInput.value;
if (keyword !== this.state.lastKeyword) {
this.setState({
lastKeyword: keyword
});
fetch(`${baseUrl}search`, {
method: 'POST',
// mode: 'no-cors',
headers: new Headers({
'Content-Type': 'application/json'
}),
// credentials: 'include',
body: JSON.stringify({keyword})
})
}
}
And My Express.js server code:
app.all('*', (req, res, next) => {
res.header("Access-Control-Allow-Origin", "*");
res.header('Access-Control-Allow-Methods', 'POST, GET, OPTIONS');
res.header('Access-Control-Allow-Headers', 'Content-Type');
// res.header('Access-Control-Allow-Credentials', true);
res.header('Content-Type', 'application/json; charset=utf-8')
next();
});
When I submit the form, I get two requests. One of them is an OPTIONS request, and another one is an POST request and the response to it is right:
As you can see, the Express server runs on port 8000, and the React development server runs on port 3000. localhost:3000
is requesting localhost:8000/search
, and localhost:8000
is requesting another origin via using a POST method. However, only the second request works well. I don't know how this happen. Of course, If I make a GET request with querystring, things are normal. But I also want to know how to make a POST fetch with the request body.
That
OPTIONS
request is sent automatically by your browser on its own, before it tries thePOST
request from your code. It’s called a CORS preflight.https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#Preflighted_requests has the details.
The gist of it in your specific case is that the
Content-Type: application/json
request header that your code is adding is what triggers the browser to do that preflightOPTIONS
request.So the purpose of that particular preflight request is for the browser to ask the server, “Do you allow cross-origin
POST
requests that have aContent-Type
header whose value isn’t one ofapplication/x-www-form-urlencoded
,multipart/form-data
, ortext/plain
?”And for the browser to consider the preflight successful, the server must send back a response with an
Access-Control-Allow-Headers
response header that includesContent-Type
in its value.So I see that you’ve got
res.header('Access-Control-Allow-Headers', 'Content-Type')
in your current server code onhttp://localhost:8000/
, and that’s the right value to set if you’re going to code it manually that way. But I think the reason that’s not working is because you don’t also have code that explicitly handlesOPTIONS
requests.To fix that, you might try instead installing the npm
cors
package:…and then doing something like this:
That’ll handle the
OPTIONS
request for you, while also sending back the right headers and values.