为什么在发出POST请求后会收到OPTIONS请求?

时间:2017-10-24 07:16:32

标签: http post cors preflight http-options-method

我的前端代码:

<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})
    })
  }
}

和我的Express.js服务器代码:

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();
});

当我提交表单时,我收到两个请求。其中一个是OPTIONS请求,另一个是POST请求,对它的响应是正确的: enter image description here enter image description here enter image description here

如您所见,Express服务器在端口8000上运行,React开发服务器在端口3000上运行。localhost:3000正在请求localhost:8000/searchlocalhost:8000正在请求另一个来源使用POST方法。但是,只有第二个请求才能正常运行。我不知道这是怎么发生的。当然,如果我使用查询字符串发出GET请求,那么事情是正常的。但我也想知道如何使用请求体进行POST提取。

2 个答案:

答案 0 :(得分:8)

在您的代码尝试OPTIONS请求之前,您的浏览器会自动发送POST个请求。它被称为CORS预检。

https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#Preflighted_requests有详细信息。

在您的具体情况下,它的要点是您的代码添加的Content-Type: application/json请求标头会触发浏览器执行预检OPTIONS请求。

因此,该特定预检请求的目的是让浏览器询问服务器,“您是否允许具有POST标头但其值不是的跨域Content-Type请求application/x-www-form-urlencodedmultipart/form-datatext/plain中的一个?“

要让浏览器认为预检成功,服务器必须发回一个带有Access-Control-Allow-Headers响应标头的响应,其值包含Content-Type

所以我看到你res.header('Access-Control-Allow-Headers', 'Content-Type')上的当前服务器代码中有http://localhost:8000/,如果您要以这种方式手动编码,那么这是正确的设置值。但我认为不起作用的原因是因为您没有明确处理OPTIONS请求的代码。

要解决此问题,您可以尝试安装npm cors包:

npm install cors

......然后做这样的事情:

var express = require('express')
  , cors = require('cors')
  , app = express();
app.options('*', cors()); // preflight OPTIONS; put before other routes
app.listen(80, function(){
  console.log('CORS-enabled web server listening on port 80');
});

这将为您处理OPTIONS请求,同时还会发回正确的标头和值。

答案 1 :(得分:-2)

我最近遇到了类似的问题,并使用FormData发送我的请求有效负载,并且您不需要发送自定义标头。 FormData对象会为您处理身份验证凭据,但是它使用SSL,并且只能与localhost不提供的https一起使用,因为本地主机使用http协议。 检查表单数据npm documentation以获得有关如何在快速应用程序中安装和使用它的详细信息,但是FormData可以在主要浏览器中使用。 这是一个简单的代码示例 npm install-保存表单数据

`

var FormData = require('form-data');
var http = require('http'); 
var form = new FormData();
 
http.request('http://nodejs.org/images/logo.png', function(response) {
  form.append('my_field', 'my value');
  form.append('my_buffer', new Buffer(10));
  form.append('my_logo', response);
});

`