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.
This pre-flight request is made by some browsers as a safety measure to ensure that the request being done is trusted by the server. Meaning the server understands that the method, origin and headers being sent on the request are safe to act upon.
Prevent sending the post data, if it wont be processed This is the only reason what is valid. Using options request will prevent sending the post data to the server unnecessarily.
The HTTP OPTIONS method requests permitted communication options for a given URL or server. A client can specify a URL with this method, or an asterisk ( * ) to refer to the entire server.
A preflight request is a small request that is sent by the browser before the actual request. It contains information like which HTTP method is used, as well as if any custom HTTP headers are present. The preflight gives the server a chance to examine what the actual request will look like before it's made.
That OPTIONS
request is sent automatically by your browser on its own, before it tries the POST
request from your code. It’s called a CORS preflight.
https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#Preflighted_requests has details.
The gist of it in this specific case is that the Content-Type: application/json
request header that the code is adding is what triggers the browser to do that preflight OPTIONS
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 a Content-Type
header whose value isn’t one of application/x-www-form-urlencoded
, multipart/form-data
, or text/plain
?”
And for the browser to consider the preflight successful, the server must send back a response with an Access-Control-Allow-Headers
header that includes Content-Type
in its value.
So I see that you’ve got res.header('Access-Control-Allow-Headers', 'Content-Type')
in your current server code on http://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 handles OPTIONS
requests.
To fix that, you might try instead installing the npm cors
package:
npm install cors
…and then doing something like this:
var express = require('express')
, cors = require('cors')
, app = express();
const corsOptions = {
origin: true,
credentials: true
}
app.options('*', cors(corsOptions)); // preflight OPTIONS; put before other routes
app.listen(80, function(){
console.log('CORS-enabled web server listening on port 80');
});
That’ll handle the OPTIONS
request, while also sending back the right headers and values.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With