cors 与 fetch 以及何时发出选项请求时非常困惑

Posted

技术标签:

【中文标题】cors 与 fetch 以及何时发出选项请求时非常困惑【英文标题】:Very confused by cors with fetch and when an options request is made 【发布时间】:2017-03-16 08:47:41 【问题描述】:

我有以下使用whatwg fetch的代码:

  const headers = new Headers();

  //uncommenting this causes the preflight options request to be sent 
  //headers.append('x-something', 'foo');

  const response = await fetch('http://localhost:5000/api/managers', 
    headers,
    credentials: 'include'
  );

除非我取消注释此行,否则上述代码不会发出预检选项请求:

 //headers.append('x-something', 'foo');

我将服务器配置为允许 localhost 请求:

app.use(cors(
  origin: 'http://localhost:4040'
));

如果我使用 credentials: 'include' 选项发出请求,我会在 chrome 浏览器中收到以下错误:

Fetch API 无法加载 http://localhost:5000/api/managers。证书 flag 为“true”,但“Access-Control-Allow-Credentials”标头为 ''。必须为“true”才能允许凭据。起源 'http://localhost:4040' 因此不允许访问。

如果我删除 credentials: 'include' 但有这样的自定义标题:

  headers.append('x-something', 'foo');

  const response = await fetch('http://localhost:5000/api/managers', 
    headers
  );

然后,chrome 网络选项卡仅显示带有 204 No Content 响应的 OPTIONS 请求,即使服务器返回了 JSON 响应。

我不明白为什么 chrome 网络选项卡没有显示带有 JSON 响应的 GET 请求。

请求和响应如下所示,带有 204 无内容响应:

Request URL:http://localhost:5000/api/managers
Request Method:OPTIONS
Status Code:204 No Content
Remote Address:[::1]:5000
Response Headers
view source
Access-Control-Allow-Headers:x-something
Access-Control-Allow-Methods:GET,HEAD,PUT,POST,DELETE,PATCH
Access-Control-Allow-Origin:http://localhost:4040
Connection:keep-alive
Date:Wed, 02 Nov 2016 21:23:24 GMT
Vary:Accept-Encoding
Request Headers
view source
Accept:*/*
Accept-Encoding:gzip, deflate, sdch, br
Accept-Language:en-US,en;q=0.8
Access-Control-Request-Headers:x-something
Access-Control-Request-Method:GET
Cache-Control:no-cache
Connection:keep-alive
Host:localhost:5000
Origin:http://localhost:4040
Pragma:no-cache
Referer:http://localhost:4040/base/winratio
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (Khtml, like Gecko) Chrome/54.0.2840.71 Safari/537.36
Name
managers
/api
info?t=1478121804370
/sockjs-node

如果我把代码写成这样:

  const response = await fetch('http://localhost:5000/api/managers', 
  );

然后谷歌浏览器网络选项卡只显示一个带有 200 HTTP 响应的 GET 请求和它返回的 json:

Request URL:http://localhost:5000/api/managers
Request Method:GET
Status Code:200 OK
Remote Address:[::1]:5000
Response Headers
view source
Access-Control-Allow-Origin:http://localhost:4040
Connection:keep-alive
Content-Length:1104
Content-Type:application/json; charset=utf-8
Date:Wed, 02 Nov 2016 21:35:21 GMT
Vary:Accept-Encoding
X-Content-Type-Options:nosniff
X-DNS-Prefetch-Control:off
X-Download-Options:noopen
X-Frame-Options:SAMEORIGIN
X-XSS-Protection:1; mode=block
Request Headers
view source
Accept:*/*
Accept-Encoding:gzip, deflate, sdch, br
Accept-Language:en-US,en;q=0.8
Cache-Control:no-cache
Connection:keep-alive
Host:localhost:5000
Origin:http://localhost:4040
Pragma:no-cache
Referer:http://localhost:4040/base/winratio
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36
Name

【问题讨论】:

developer.mozilla.org/en-US/docs/Web/HTTP/… 【参考方案1】:

“有些请求不会触发 CORS 预检。在本文中这些请求称为“简单请求”,尽管 Fetch 规范(定义 CORS)没有使用该术语。”

继续阅读https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#Simple_requests

【讨论】:

【参考方案2】:

如错误消息所示,您的服务器需要将Access-Control-Allow-Credentials: true 作为响应标头。这在 Fetch 中也有解释:https://fetch.spec.whatwg.org/#cors-protocol-and-credentials

【讨论】:

以上是关于cors 与 fetch 以及何时发出选项请求时非常困惑的主要内容,如果未能解决你的问题,请参考以下文章

Fetch API 无法加载,cors

如何在 fetch 中执行跨域请求以及异步等待? (CORS 错误)[重复]

从 Blazor 发出 CORS 请求时如何包含凭据?

从服务工作者发送的 CORS 预检请求,但不是来自常规请求

发出 POST 请求时出现 Google Cloud Function CORS 错误

本地 Javascript Fetch Post 请求失败,调用 ASP.NET Core 2.2 Web API。 CORS 已启用