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

34

摘要:

我有一个页面使用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头信息。这将被缓存,随后的CORS请求(那些在请求头中设置了来源的请求)将被拒绝,因为浏览器使用缓存中的非CORS版本。最好的解决方法是什么?我能否设置某些内容,使得非CORS版本永远不会被缓存?我应该通过在请求的URL末尾添加一个“?some_flag”来区分CORS请求吗?理想情况下,即使请求不包含“origin”,我也希望S3始终发送所需的CORS标头。

你使用的是哪个浏览器?这种行为在所有浏览器中都出现吗?听起来像是浏览器的错误。你提出的查询参数解决方案听起来是一个不错的解决方法。 - monsur
添加了“编辑:在Safari 5.1.6和Chrome 21.0.1180.89中都失败。在Firefox 14中运行良好。” - Wes
1
那很可能是一个 WebKit 的 bug。这听起来像是同样的问题:https://bugs.webkit.org/show_bug.cgi?id=63090 这个 bug 建议添加头部 "Vary: Origin" 可能会解决这个问题。 - monsur
3
该问题也已在AWS S3论坛上报告。 - Kristian Hanekamp
5个回答

9
我遇到了同样的问题。正如@monsur所说,问题在于S3没有设置"Vary: Origin"头,尽管它应该这样做。不幸的是,据我所知,没有办法让S3发送该标头。但是,在需要CORS时,您可以通过向请求添加查询字符串参数(例如?origin=example.com)来解决此问题。查询字符串强制浏览器不使用缓存资源。
理想情况下,当启用CORS时,CloudFront和S3将发送Vary:Origin头,或者Webkit会隐式变化原点头,我认为Firefox会这样做,因此它没有这个问题。

6

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

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

这将始终强制进行未缓存的响应,因为毫秒级日期始终会产生浏览器尚未知道的不同URL,但我不确定这是否解决了您的问题。


3
一种解决方案是在 img 标签上设置 crossorigin='use-credentials' 属性,强制浏览器始终执行 CORS 请求。参见此处:https://dev59.com/UVwZ5IYBdhLWcg3wM97Z#34496683 另一种解决方案是配置 CloudFront 分发自动将非 CORS 请求转换为 CORS 请求。这可以通过向每个请求 CloudFront 发送到 S3 的请求添加 CORS 头来实现,使用最近添加的 CloudFront 功能“控制边缘到源请求标头”。
此处查看功能公告: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

2
我也遇到了这个问题。最终我在我的S3存储桶前设置了一个CloudFront分发,然后在CloudFront的“Origin Settings”部分中设置了“Origin Custom Headers”选项,将“Origin: https://example.com”发送到我的S3源。这会导致S3始终提供CORS标头,因为它始终会看到“Origin”请求标头。为了做到这一点,您必须确保“Origin”标头未被任何CloudFront行为列入白名单。
简而言之:我告诉CloudFront向我的S3源的每个请求发送“Origin: https://example.com”,并通过CloudFront提供我的内容。

0

在进行CORS请求后,您可以使用JavaScript附加img标签。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接