执行预检请求时是不是需要 Access-Control-Allow-Origin CORS 标头?

Posted

技术标签:

【中文标题】执行预检请求时是不是需要 Access-Control-Allow-Origin CORS 标头?【英文标题】:Is the Access-Control-Allow-Origin CORS header required when doing a preflight request?执行预检请求时是否需要 Access-Control-Allow-Origin CORS 标头? 【发布时间】:2015-02-06 15:05:59 【问题描述】:

我们在我们的网站上看到了众所周知的 CORS 错误:

XMLHttpRequest 无法加载 https://my-site.com/api。请求的资源上不存在“Access-Control-Allow-Origin”标头。 Origin 'https://my-other-site.com' 因此不允许访问。

问题是,Access-Control-Allow-Origin 在预检请求中设置正确...

OPTIONS https://my-site.com/api HTTP/1.1
Host: my-site.com
Access-Control-Request-Method: POST
Origin: https://my-other-site.com
Access-Control-Request-Headers: my-custom-header, accept, content-type
Accept: */*
Referer: https://my-other-site.com/
...other stuff...


HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://my-other-site.com
Access-Control-Allow-Methods: POST
Access-Control-Allow-Headers: my-custom-header, accept, content-type
Access-Control-Expose-Headers: my-custom-header
...other stuff...

...但是,它没有在后续请求中设置。

POST https://my-site.com/api HTTP/1.1
Host: my-site.com
Accept: */*
My-Custom-Header: abcd123
Origin: https://my-other-site.com
Referer: https://my-other-site.com/
...other stuff...


HTTP/1.1 200 OK
My-Custom-Header: abcd123
...other stuff...

我不明白这个问题。根据我在网上阅读的一切,如果我们使用预检请求,我们不需要为实际请求添加 CORS 标头。但是,显然情况并非如此。

所有示例here 和here 在实际响应中都包含Access-Control-Allow-Origin 标头,但不包含任何其他“必需” CORS 标头。当我们将那个标头添加到我们的实际响应中时,错误就消失了。


所以我的问题是,两个请求中实际上都需要 Access-Control-Allow-Origin 标头吗?这是在哪里说明的?为什么这是真的?

【问题讨论】:

【参考方案1】:

是的,看起来两个响应都应该包含必要的 CORS 标头。

在Simple Cross-Origin Request 和Cross-Origin Request with Preflight 中,“实际请求”遵循相同的行为,无论预检如何(分别为第 1 步和第 3 步)都检查 CORS 标头。

    [...] 应用make a request steps 并在发出请求时遵守以下请求规则

    ...(截断:3xx 代码、中止和网络错误)

    否则

    执行resource sharing check。 [...]

给定资源的资源共享检查算法如下:

    如果响应包含零个或多个Access-Control-Allow-Origin 标头值,则返回失败并终止此算法。

    [...]

预检请求只会阻止“实际请求”的开始。

【讨论】:

““实际请求”遵循相同的行为,无论预检如何都检查 CORS 标头” - 但这似乎不是真的。实际请求在没有 Access-Control-Allow-MethodsAccess-Control-Allow-Headers 标头的情况下正常工作。然而(正如我现在刚刚发现的),似乎Access-Control-Expose-Headers 标头在预检和实际请求中都是 所必需的。 WTF!?

以上是关于执行预检请求时是不是需要 Access-Control-Allow-Origin CORS 标头?的主要内容,如果未能解决你的问题,请参考以下文章

是否可以向 CORS 预检请求添加请求标头?

AWS API Gateway CORS 问题 - JS

预检时间的 CORS 请求是不是耗时?

浏览器中的preflight请求-预检请求

使用子域时防止预检选项

如果我在使用 cors 时添加标准 http 标头,为啥会预检请求?