缓存的非CORS响应与新的CORS请求冲突

时间:2012-09-19 16:11:43

标签: caching amazon-s3 xmlhttprequest cors

要点:

我有一个页面使用来自s3(HTML img标记)的图片的标记加载,我有一个使用xmlhttprequest的页面。标记加载在没有CORS头的情况下进行缓存,因此xmlhttprequest会看到缓存版本,检查它的标题并因交叉原点错误而失败。

详细信息:

编辑:safari 5.1.6和chrome 21.0.1180.89都失败了。在Firefox 14中正常工作。

使用S3的新CORS,我设置CORSRule如下:

<CORSRule>
  <AllowedOrigin>*</AllowedOrigin>
  <AllowedMethod>GET</AllowedMethod>
  <AllowedMethod>HEAD</AllowedMethod>
  <MaxAgeSeconds>0</MaxAgeSeconds>
  <AllowedHeader>*</AllowedHeader>
</CORSRule>

如果我从S3请求图像而未在请求标头中设置原点,我会在响应中返回没有任何CORS标头的图像。

这个get的缓存和随后的CORS请求(一个在请求头中设置原点的请求)被拒绝,因为浏览器使用非CORS版本形成缓存。

解决这个问题的最佳方法是什么?我可以设置一些东西,以便非CORS版本永远不会被缓存吗?我应该通过将?some_flag附加到请求的网址来区分CORS请求吗?

理想情况下,即使请求不包含“origin”,我也总是会发回所需的CORS标头。

5 个答案:

答案 0 :(得分:9)

我遇到了同样的问题。正如@monsur所说,问题是S3没有设置“Vary:Origin”标题,即使它应该。不幸的是,据我所知,没有办法让S3发送该标头。但是,您可以通过在需要CORS时向请求(例如?origin=example.com)添加查询字符串参数来解决此问题。查询字符串强制浏览器不使用缓存资源。

理想情况下,当启用CORS时,cloudfront和S3将发送Vary:Origin标头和/或Webkit会在Origin标头上隐式变化,我认为Firefox会这样做,因为它没有这个问题。

答案 1 :(得分:6)

它绝对不是最佳方式,但您可以通过向请求添加一些url参数来禁用图像请求的缓存。通常,这是通过javascript完成的,例如:

var img = document.createElement('img');
img.setAttribute('src', yourRequestUrl + '?d=' + Date.now());
tagToAppendImg.appendChild(img);

这将始终强制执行未缓存的响应,因为以毫秒为单位的日期始终会生成浏览器尚不知道的其他URL,但我不确定这是否可以解决您的问题。

答案 2 :(得分:2)

一种解决方案是在crossorigin='use-credentials' - 标记上设置img属性以强制浏览器始终执行CORS请求,请参阅此处:https://stackoverflow.com/a/34496683/725542

另一种解决方案是配置您的CloudFront分配以自动将非CORS请求转换为CORS请求。这可以通过使用最近添加的CloudFront功能“控制边缘到源请求标头”向CloudFront发送到S3的每个请求添加CORS标头。

请在此处查看功能公告: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

答案 3 :(得分:0)

您可以在提出CORS请求后使用Javascript附加img标记。

答案 4 :(得分:0)

我也遇到了这个问题。我最终在我的S3存储桶前设置了一个云端分发,并在cloudfront的Origin Custom Headers部分设置了Origin Settings选项,以便将Origin: https://example.com发送到我的S3源。这会导致S3始终为CORS标头提供服务,因为它始终会看到Origin请求标头。为此,您必须确保Origin标头未被任何云端行为列入白名单。

tl; dr:我告诉cloudfront向我的S3源发送每个请求Origin: https://example.com,并通过cloudfront提供我的内容。