Amazon S3 CORS(跨域资源共享)和Firefox跨域字体加载


134

Firefox存在一个长期存在的问题,即不加载与当前网页不同来源的字体。通常,在CDN上提供字体时会出现问题。

在其他问题上提出了各种解决方案:

CSS @ font-face不适用于Firefox,但适用于Chrome和IE

随着Amazon S3 CORS的推出,是否存在使用CORS解决Firefox中字体加载问题的解决方案?

编辑:非常高兴看到S3 CORS配置的样本。

edit2:我找到了一个可行的解决方案,但实际上并没有理解它的作用。如果任何人都可以提供有关配置的更详细的解释以及亚马逊解释配置时发生的背景魔术,那将不胜感激,就像nzifnab为其提供赏金一样。

Answers:


148

2014年9月10日更新:

由于Cloudfront现在已正确支持CORS,因此您不再需要执行以下任何查询字符串技巧。请参阅http://aws.amazon.com/blogs/aws/enhanced-cloudfront-customization/和此答案以获取更多信息:https : //stackoverflow.com/a/25305915/308315


好的,我终于通过下面的配置使字体工作了,对文档中的示例进行了一些调整。

我的字体托管在S3上,但在Cloudfront前面。

我不确定为什么会起作用,我的猜测可能是<AllowedMethod> GET<AllowedHeader> Content-*所需要的。

如果精通Amazon S3 CORS配置的任何人都可以对此有所了解,将不胜感激。

<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
    <CORSRule>
        <AllowedOrigin>https://mydomain.com</AllowedOrigin>
        <AllowedMethod>GET</AllowedMethod>
        <MaxAgeSeconds>3000</MaxAgeSeconds>
        <AllowedHeader>Content-*</AllowedHeader>
        <AllowedHeader>Host</AllowedHeader>
    </CORSRule>
    <CORSRule>
        <AllowedOrigin>https://*.mydomain.com</AllowedOrigin>
        <AllowedMethod>GET</AllowedMethod>
        <MaxAgeSeconds>3000</MaxAgeSeconds>
        <AllowedHeader>Content-*</AllowedHeader>
        <AllowedHeader>Host</AllowedHeader>
    </CORSRule>
</CORSConfiguration>

编辑:

一些开发人员面临Cloudfront缓存Access-Control-Allow-Origin标头的问题。AWS工作人员已在下面的链接(https://forums.aws.amazon.com/thread.jspa?threadID=114646)中解决了此问题,@ Jeff-Atwood对此进行了评论。

作为一种解决方法,建议从链接线程使用查询字符串来区分来自不同域的调用。我将在这里重现简短的示例。

使用curl检查响应头:

域A:a.domain.com

curl -i -H "Origin: https://a.domain.com" http://hashhashhash.cloudfront.net/font.woff?https_a.domain.com

来自域A的响应头:

Access-Control-Allow-Origin: https://a.domain.com
Access-Control-Allow-Methods: GET
Access-Control-Max-Age: 3000
Access-Control-Allow-Credentials: true
X-Cache: Miss from Cloudfront

域B:b.domain.com

curl -i -H "Origin: http://b.domain.com" http://hashhashhash.cloudfront.net/font.woff?http_b.domain.com

来自域B的响应头:

Access-Control-Allow-Origin: http://b.domain.com
Access-Control-Allow-Methods: GET
Access-Control-Max-Age: 3000
Access-Control-Allow-Credentials: true
X-Cache: Miss from Cloudfront

您会注意到,Access-Control-Allow-Origin已经返回了不同的值,这些值已经超过了Cloudfront缓存。


2
您是否遇到过与此处描述的问题类似的问题- Access-Control-Allow-Origin通过其他子域发出后续请求时,标头会被缓存并使CORS无效?
2012年

1
@ov我没有遇到问题,因为我明确设置了使用资源的域。我已经阅读了您之前发布的链接。我隐约记得对另一个线程的一些答复,说必须明确声明域,因此由于某些限制,实际上不允许使用<AllowedOrigin> * </ AllowedOrigin>。我现在找不到这些回复帖子,可能是我在其他地方阅读的博客帖子。希望有帮助。
VKen

3
您可以在单个CORSRule元素中包含多个AllowedOrigin元素,因此您可以将这些CORSRule合并为一个元素,因为它们中的其他元素相同。
Ben Hull

4
@dan(如果S3存储桶由CloudFront提供),答案似乎是按此官方Amazon答案中所述按域更改字体查询字符串forums.aws.amazon.com/thread.jspa?threadID=114646
Jeff Atwood

2
这是一个非常令人沮丧的问题。好消息是S3现在看来做对了,因此至少可以通过CloudFront提供除Webfonts之外的所有内容,并直接从S3提供字体文件。可悲的是,如果没有更重大的重构,querystring hack在我们的应用程序中是不实际的,因为资产都是通过Rails资产管道提供的,并且没有方便的方法来在请求时调整资产URL(它们都是在部署期间生成的)资产预编译时)。CSS中的字体URL已在S3上打开。
Zach Lipton

97

经过一些调整后,我似乎可以在没有查询字符串hack的情况下使用它。此处提供更多信息:http : //docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/RequestAndResponseBehaviorS3Origin.html#RequestS3-cors

我将经历整个设置过程,以便轻松查看我所做的事情,希望这对其他人有帮助。

背景信息:我正在使用一个具有asset_sync gem的Rails应用程序将资产放到S3上。这包括字体。

在S3控制台中,我单击了我的存储桶,属性和“ edit cors配置”,此处: CORS配置按钮

在文本区域内,我有类似以下内容:

<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
    <CORSRule>
        <AllowedOrigin>https://*.example.com</AllowedOrigin>
        <AllowedMethod>GET</AllowedMethod>
        <MaxAgeSeconds>3000</MaxAgeSeconds>
        <AllowedHeader>*</AllowedHeader>
    </CORSRule>
</CORSConfiguration>

然后在Cloudfront面板(https://console.aws.amazon.com/cloudfront/home)中,创建了一个发行版,添加了一个指向我的S3存储桶的Origin 添加原点

然后为默认路径添加了一个行为,以指向基于S3的原点I设置。我还要做的是单击白名单标题并添加Origin添加行为和白名单标题

现在发生的事情如下,我认为这是正确的:

1)检查S3标头设置正确

curl -i -H "Origin: https://example.com" https://s3.amazonaws.com/xxxxxxxxx/assets/fonts/my-cool-font.ttf
HTTP/1.1 200 OK
x-amz-id-2: Ay63Qb5uR98ag47SRJ91+YALtc4onRu1JUJgMTU98Es/pzQ3ckmuWhzzbTgDTCt+
x-amz-request-id: F1FFE275C0FBE500
Date: Thu, 14 Aug 2014 09:39:40 GMT
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Methods: GET
Access-Control-Max-Age: 3000
Access-Control-Allow-Credentials: true
Vary: Origin, Access-Control-Request-Headers, Access-Control-Request-Method
Cache-Control: public, must-revalidate, proxy-revalidate, max-age=180
Last-Modified: Mon, 09 Dec 2013 14:29:04 GMT
ETag: "98918ee7f339c7534c34b9f5a448c3e2"
Accept-Ranges: bytes
Content-Type: application/x-font-ttf
Content-Length: 12156
Server: AmazonS3

2)检查Cloudfront是否与标头一起使用

curl -i -H "Origin: https://example.com" https://xxxxx.cloudfront.net/assets/fonts/my-cool-font.ttf
HTTP/1.1 200 OK
Content-Type: application/x-font-ttf
Content-Length: 12156
Connection: keep-alive
Date: Thu, 14 Aug 2014 09:35:26 GMT
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Methods: GET
Access-Control-Max-Age: 3000
Access-Control-Allow-Credentials: true
Cache-Control: public, must-revalidate, proxy-revalidate, max-age=180
Last-Modified: Mon, 09 Dec 2013 14:29:04 GMT
ETag: "98918ee7f339c7534c34b9f5a448c3e2"
Accept-Ranges: bytes
Server: AmazonS3
Vary: Origin
X-Cache: Miss from cloudfront
Via: 1.1 77bdacfea247b6cbe84dffa61da5a554.cloudfront.net (CloudFront)
X-Amz-Cf-Id: cmCxaUcFf3bT48zpPw0Q-vDDza0nZoWm9-_3qY5pJBhj64iTpkgMlg==

(请注意,上面的内容是Cloudfront遗漏的内容,因为这些文件被缓存了180秒,但对匹配而言却一样)

3)使用其他来源(但CORS允许S3存储桶使用的来源)击中Cloudfront- Access-Control-Allow-Origin不会被缓存!好极了!

curl -i -H "Origin: https://www2.example.com" https://xxxxx.cloudfront.net/assets/fonts/my-cool-font.ttf
HTTP/1.1 200 OK
Content-Type: application/x-font-ttf
Content-Length: 12156
Connection: keep-alive
Date: Thu, 14 Aug 2014 10:02:33 GMT
Access-Control-Allow-Origin: https://www2.example.com
Access-Control-Allow-Methods: GET
Access-Control-Max-Age: 3000
Access-Control-Allow-Credentials: true
Cache-Control: public, must-revalidate, proxy-revalidate, max-age=180
Last-Modified: Mon, 09 Dec 2013 14:29:04 GMT
ETag: "98918ee7f339c7534c34b9f5a448c3e2"
Accept-Ranges: bytes
Server: AmazonS3
Vary: Origin
X-Cache: Miss from cloudfront
Via: 1.1 ba7014bad8e9bf2ed075d09443dcc4f1.cloudfront.net (CloudFront)
X-Amz-Cf-Id: vy-UccJ094cjdbdT0tcKuil22XYwWdIECdBZ_5hqoTjr0tNH80NQPg==

请注意,上面的域已成功更改,没有查询字符串被黑客入侵。

当我更改Origin标头时,似乎总是X-Cache: Miss from cloudfront在第一个请求上出现,然后我得到预期的结果X-Cache: Hit from cloudfront

PS值得注意的是,在执行curl -I(大写I)时,它不会显示Access-Control-Allow-Origin标头,因为它只是一个HEAD,所以我会执行-i使它成为GET并向上滚动。


当其他所有人都不工作时工作。感谢您抽出宝贵时间发布如此详细的信息!
iwasrobbed

有用!!仅供参考-我在测试时这个......要编辑的答案,使用该卷曲解决方案...有一个巨大的HTTP响应文本stackoverflow.com/questions/10060098/...
迈克尔·戈勒姆

很好,谢谢大家-很高兴看到它对其他人有用。
Eamonn Gahan 2014年

我无法告诉您您对我们的帮助!+1
没什么特别的,这里

1
1,用于将顾客头部Origin来自观众,使得高速缓存的Cloudfront基于该头中的对象(以及转发服务器CORS标头返回给用户)
塞巴斯蒂安索尼尔

13

我的字体可以正确使用,直到最后一次推送到Heroku为止。我不知道为什么,但是CORS允许原点的通配符停止工作。我在存储桶设置中将我的所有prepro和pro域都添加到了CORS策略中,所以现在看起来像这样:

<CORSConfiguration>
    <CORSRule>
        <AllowedOrigin>http://prepro.examle.com</AllowedOrigin>
        <AllowedOrigin>https://prepro.examle.com</AllowedOrigin>
        <AllowedOrigin>http://examle.com</AllowedOrigin>
        <AllowedOrigin>https://examle.com</AllowedOrigin>
        <AllowedMethod>GET</AllowedMethod>
        <MaxAgeSeconds>3000</MaxAgeSeconds>
        <AllowedHeader>Authorization</AllowedHeader>
    </CORSRule>

</CORSConfiguration>

更新:添加您的http://localhost:PORT


1
感谢您分享此解决方案。这对我有用。
瑞安·蒙哥马利

8

好的,文档指出您可以将配置保留为“存储桶中的cors子资源”。我的意思是,我将使用配置在存储桶的根部创建一个名为“ cors”的文件,但这将无法正常工作。最后,我必须登录到Amazon S3管理区域,并在properties存储桶对话框中。

S3可以使用一些更好的文档...


1
是的,但是我很幸运在属性面板上发现了一些新的界面更改。我一直在编辑存储桶策略,因此自然而然地在同一面板中寻找CORS配置。
VKen

为我工作,我想在我的应用程序中设置它,谁知道它是如此简单
Richlewis 2013年

7

在Amazon S3 CORS配置(S3存储桶/权限/ CORS)中,如果您使用此功能:

<?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>

CORS适用于Javascript和CSS文件,但不适用于Font文件

您必须使用@VKen答案中表示的模式指定域以允许CORS:https://stackoverflow.com/a/25305915/618464

因此,使用此

<?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>
<CORSRule>
    <AllowedOrigin>https://*.mydomain.com</AllowedOrigin>
    <AllowedMethod>GET</AllowedMethod>
    <MaxAgeSeconds>3000</MaxAgeSeconds>
    <AllowedHeader>*</AllowedHeader>
</CORSRule>
</CORSConfiguration>

请记住将您的域替换为“ mydomain.com”。

之后,使CloudFront缓存无效(CloudFront / Invalidations / Create Invalidation),它将起作用。


6

就我而言,我没有在CORS配置中定义XML名称空间和版本。定义那些有效的方法。

已变更

<CORSConfiguration>

<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">

也为我工作。我的字体托管在存储桶本身中。
khamaileon,2014年

为什么默认模板不自动包含此内容超出了我的范围。
CoatedMoose

4

有更好更好的方法!

我个人更喜欢使用我的DNS子域来解决此问题。如果我的CDN位于cdn.myawesomeapp.com而不是sdf73n7ssa.cloudfront.net后面,那么浏览器将不会发疯并将其阻止为跨域安全问题。

要将您的子域指向您的AWS Cloudfront域,请转到AWS Cloudfront控制面板,选择您的Cloudfront分布,然后在“备用域名(CNAME)”字段中输入您的CDN子域。像cdn.myawesomeapp.com这样的东西就可以。

现在,您可以转到您的DNS提供商(例如AWS Route 53),并为cdn.myawesomeapp.com创建一个指向sdf73n7ssa.cloudfront.net的CNAME。

http://blog.cloud66.com/cross-origin-resource-sharing-cors-blocked-for-cloudfront-in-rails/


这会破坏SSL,或者使用SSL花费大量金钱,因此很多人不这样做。
maletor '16

4

此配置对我有用。我可以列出对象,检索,更新和删除。

<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
  <CORSRule>
    <AllowedOrigin>http://localhost:3000</AllowedOrigin>
    <AllowedMethod>HEAD</AllowedMethod>
    <AllowedMethod>GET</AllowedMethod>
    <AllowedMethod>PUT</AllowedMethod>
    <AllowedMethod>POST</AllowedMethod>
    <AllowedMethod>DELETE</AllowedMethod>
    <AllowedHeader>*</AllowedHeader>
    <ExposeHeader>ETag</ExposeHeader>
    <ExposeHeader>x-amz-meta-custom-header</ExposeHeader>
  </CORSRule>
</CORSConfiguration>

您需要更改域,就像我在localhost上进行的测试一样,只需在此页面查看CORS:docs.aws.amazon.com/AWSJavaScriptSDK/guide/…–
Shahid

1
<ifModule mod_headers.c>

   Header set Access-Control-Allow-Origin: http://domainurl.com

</ifModule>

简单的解决方案


感谢分享!给我一个想法,就是在静态资产上传到云存储时,仅将此标头添加为“元数据”(尽管那样,它只能与1 或一起使用particular domainall domains
Vinay Vissh '18

0

重新启动我的spring boot应用程序(服务器)可以为我解决问题。

我已经在S3上正确配置了CORS。卷毛使用原始标头给出了正确的响应。Safari正在正确获取字体。只是铬不愿意接受CORS。

不知道是什么导致了该行为。必须与If-modified-since有关


0

这与字体无关,而与图像有关,这可能是一种边缘情况,但就我而言,可能是另一种情况。我将其保留在此处,希望对您有所帮助:

如果您处在“我已经完成了他们所告诉的一切,但仍然行不通”的场景中,很可能是Chrome和Safari中与缓存相关的问题。假设您的服务器具有正确的CORS配置集:

<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
    <CORSRule>
        <AllowedOrigin>*</AllowedOrigin>
        <AllowedMethod>GET</AllowedMethod>
        <MaxAgeSeconds>3000</MaxAgeSeconds>
    </CORSRule>
</CORSConfiguration>

在Firefox中一切正常,但在Chrome和Safari中则无法。如果你访问到您的远程图像路径简单的<img src="http://my.remote.server.com/images/cat.png">标签和一个js图像元素的src,如以下方式:

var myImg = new Image()
myImg.crossOrigin = 'Anonymous'
myImg.onload = () => {
  // do stuff (maybe draw the downloaded img on a canvas)
}
myImg.src = 'http://my.remote.server.com/images/cat.png'

您可能会No 'Access-Control-Allow-Origin'在Chrome和Safari中获得错误。发生这种情况是因为第一种<img>方式会弄乱浏览器缓存,并且当您稍后尝试访问同一图像时(在代码内Image元素上),它只会中断。为了避免这种情况,您可以在一个.src路径中添加一个虚拟的GET参数,以强制浏览器重新请求图像并避免使用缓存,如下所示:

<img src="http://my.remote.server.com/images/cat.png?nocache=true"></img>

-1

当然是。Firefox支持CORS字体,就像http://dev.w3.org/csswg/css3-fonts/#allowing-cross-origin-font-loading中的规范要求一样


感谢您的迅速答复,鲍里斯·扎巴尔斯基(Boris Zbarsky)。您能否显示S3 CORS设置的一些示例配置?
VKen 2012年

我从没考虑过配置S3 ...就在HTTP级别上发送的内容而言,如果可以,只需在HTTP响应中为字体文件发送“ Access-Control-Allow-Origin:*”应该管用。
鲍里斯·扎巴尔斯基

谢谢,我正试图找出如何使用S3 CORS配置进行该设置的方法。
VKen 2012年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.