S3 CORS,始终发送 Vary: Origin

S3 CORS, always send Vary: Origin

我在启用了 CORS 的 Cloudfront 后面使用 S3 存储桶。如果客户端使用 Origin header 发出请求,则 S3(和 cloudfront)以 "Vary: Origin" header 响应,但是如果请求是在没有 Origin 的情况下发出的,则 header那么响应不包含任何 Vary Header.

这是有问题的,因为我在 img 标签中使用了来自 cloudfront/s3 的资源,在这种情况下,浏览器发出没有来源 header 的请求,然后再发出 ajax 请求所述图像。然后浏览器使用图像的缓存版本,没有 Access-Control-Allow-Origin header,因此拒绝请求。

有没有办法让 S3 始终 return "Vary: Origin" header?

我创建了一个帐户只是为了回答你的问题,因为对于这类问题(以及一些相关问题),周围很少有好的答案。

您描述的问题由于某种原因主要发生在 chrome,FF 和 IE 似乎足够聪明,不会在这些情况下 AJAX 和常规调用之间共享缓存。

问题

让我们先为未来的读者描述为什么会出现这个问题:

  • 浏览器 (Chrome) 使用常规 <img><script> 标签询问服务器。如果服务器在同一域中,则它不包含 CORS headers.
  • 服务器 (S3) returns 资源。如果请求中没有 Origin header,它不会在回复中附加 CORS header,因为它们是多余的。
  • 浏览器 (Chrome) 尝试使用 AJAX 再次获取资源,但这次并没有真正访问服务器,而是查看缓存的资源。
  • 浏览器(Chrome)缓存版本没有CORS headers。它会因 Access-Control-Allow-Origin 违规或其他相关问题而放弃请求。

解决方案

在HTML5中有一个名为crossorigin的属性,可以将其添加到标签中以表示它们需要发送来源信息。 可能的值为 crossorigin='anonymous'crossorigin='use-credentials' 这些与所提问题完全无关,但正如文档中所述:

By default (that is, when the attribute is not specified), CORS is not used at all.

https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_settings_attributes

所以只需像这样创建您的图像标签 <img src='cloundfront.path' crossorigin='use-credentials'>

就是这样。它非常晦涩,所以我希望这个答案能为一群人节省一些研究时间。

另一种解决方案是将您的 CloudFront 分配配置为自动将 Non-CORS 请求转换为 CORS 请求。这可以通过使用最近添加的 CloudFront 功能 "Control Edge-To-Origin Request Headers".

向 CloudFront 发送到 S3 的每个请求添加 CORS header 来实现

在此处查看功能公告:https://aws.amazon.com/blogs/aws/cloudfront-update-https-tls-v1-1v1-2-to-the-origin-addmodify-headers/

以及此处的文档:http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/forward-custom-headers.html

我偶然发现了一种让 Cloudfront 始终添加“Vary: Origin”header 的简单方法,尽管据我所知没有记录:您可以强制使用“Vary”header在 CloudFront 缓存键中包含“Origin”。

在 Cloudfront 分布上单击“编辑行为”,找到标题“缓存键和源请求”。如果您使用的是“旧版缓存设置”,请单击“添加 header”下的 select“来源”。如果您使用较新的缓存策略,则需要单击“创建策略”并在“缓存键设置”下添加源,然后返回并使用您刚刚创建的策略。

我的用例是 HMTL5 视频字幕轨道,如果您使用 crossorigin="anonymous",则不会发送 Origin,如果没有 Origin,则没有 Vary: Origin。