无法在Safari中加载跨源图像(来自CloudFront)

Rob*_*yon 14 javascript safari amazon-s3 amazon-cloudfront

尝试从Safari 8中的CloudFront URL加载图像时出现以下错误:
Cross-origin image load denied by Cross-Origin Resource Sharing policy.

这只发生在Safari 8上.在FireFox 38和Chrome 41最新版中它加载得很好.(Mac 10.10)

我的设置:

1.具有以下CORS配置的S3存储桶

<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
    <CORSRule>
        <AllowedOrigin>*</AllowedOrigin>
        <AllowedMethod>GET</AllowedMethod>
        <MaxAgeSeconds>3000</MaxAgeSeconds>
        <AllowedHeader>*</AllowedHeader>
    </CORSRule>
</CORSConfiguration>
Run Code Online (Sandbox Code Playgroud)

2.链接的CloudFront分配

以下标题已列入白名单(在行为下):

  • Access-Control-Request-Headers
  • Access-Control-Request-Method
  • Origin

3. JavaScript

var img = new Image();
img.crossOrigin = '';
img.onload = function() {
  console.log('image loaded');
}
Run Code Online (Sandbox Code Playgroud)

我尝试过的:

1.检查curl返回的标头

图像返回正确的标题(特别是Access-Control-Allow-Origin)

> curl -sI -H 'Origin: localhost' -H 'Access-Control-Request-Method: GET' http://foo.cloudfront.com/image.jpg
...
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET
Access-Control-Max-Age: 3000
Server: AmazonS3
Vary: Origin,Access-Control-Request-Headers,Access-Control-Request-Method
X-Cache: Hit from cloudfront
Run Code Online (Sandbox Code Playgroud)

2.在浏览器中检查返回的标题

有趣的是,图像并没有Access-Control-Allow-Origin: *在所有三个浏览器中返回标题.为什么会这样呢?

3.向URL添加查询字符串

向正在加载的URL添加查询字符串(例如?foo)会导致Access-Control-Allow-Origin在浏览器中返回标题,并允许在Safari中加载图像!这很好,但为什么添加查询字符串允许它工作(并返回Access-Control-Allow-Origin标题)?

4.从S3存储桶加载映像(未绑定到CloudFront分配)

从与CloudFront无关的另一个桶(具有相同的CORS配置)加载图像在Safari中也可以正常工作.

这最初让我相信这是一个特别是CloudFront问题,但上面的查询字符串让我想到了.

这让我非常沮丧.任何人都可以帮助阐明以上内容吗?


更新

谢谢你的回复.令人沮丧的是,我似乎无法复制这个问题.

下面是一个片段,它可以加载两个图像(一个来自一个S3存储桶,另一个来自各自的Cloudfront发行版),它们似乎也可以很好地加载你期望的标题,这与我上面在第2点中所说的相反.

不幸的是,我并没有真正接近一个明确的答案,但是现在我只是想把它归结为我的错误,可能会在我的CORS设置之前请求一张图片,正如Derek建议的那样.

var img, imgCloudfront;

img = new Image();
img.crossOrigin = '';
img.onload = function() {
  $('body').append('image loaded<br>');
}
img.src = 'http://sandbox-robinpyon.s3.amazonaws.com/test.jpg';

imgCloudfront = new Image();
imgCloudfront.crossOrigin = '';
imgCloudfront.onload = function() {
 $('body').append('image (cloudfront) loaded<br>');
}
imgCloudfront.src = 'http://d32d4njimxij7s.cloudfront.net/test.jpg';
Run Code Online (Sandbox Code Playgroud)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
Run Code Online (Sandbox Code Playgroud)

Der*_*rek 7

双重检查您的云端行为设置.您是否添加了自定义标题Origin?它应该是Access-Control-Allow-Origin.我最近也设置了cloudfront,发现这篇文章很有帮助:http://kennethjiang.blogspot.com/2014/07/set-up-cors-in-cloudfront-for-custom.html

我在清除云端缓存方面遇到了问题.如果您在CORS设置之前请求了图像,那么Cloudfront可能会返回之前的图像,因此您的新配置不会被反映出来.您可以尝试运行失效,它是云端行为选项卡之一.我得到了不一致的结果.如果您想确保它正常工作,请上传新图像并进行测试.我正在使用rails,有时我会提高资产版本,这会导致我的所有资产都有一个新的指纹并解决了缓存问题,因为每个文件都有一个新名称.)

关于查询字符串的问题.您可能从云端获得了缓存缺失.您可以尝试使用curl重复练习,以查看X-Cache: Hit from cloudfront是否存在响应.在云端行为设置中,有一个"转发查询字符串"的配置.这可能是一个因素.

在我的设置中,我有一个中间清漆缓存,所以我不得不弄乱它,以确保所有标头通过.看起来不像你有,但这是值得注意的.


小智 5

请参阅:https://stackoverflow.com/a/13147554/1994767

Access-Control-Allow-Headers(<AllowedHeader>*</AllowedHeader>)标头不允许使用通配符.它必须完全匹配:http://www.w3.org/TR/cors/#access-control-allow-headers-response-header