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

长期以来,Firefox 一直存在一个问题,即没有从与当前网页不同的来源加载字体。通常,当字体在 CDN 上使用时会出现这个问题。

在其他问题上提出了各种解决办法:

CSS@font-face 不支持 Firefox,但支持 Chrome 和 IE

随着 Amazon S3 CORS 的引入,是否有一种解决方案可以使用 CORS 来解决 Firefox 中的字体加载问题?

编辑: 如果能看到 S3 CORS 配置的示例就太好了。

编辑2: 我找到了一个可行的解决方案,但是并没有真正理解它是做什么的。如果有人能够提供更详细的配置解释和背景魔术发生在亚马逊的配置解释,这将是非常感谢,因为 nzifnab 谁提供了它的赏金。

98779 次浏览

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

更新于2014年9月10日:

由于 Cloudfront 现在正确地支持 CORS,因此您不再需要执行下面的任何查询字符串修改。更多信息参见 http://aws.amazon.com/blogs/aws/enhanced-cloudfront-customization/和这个答案: https://stackoverflow.com/a/25305915/308315


好的,我最终使用下面的配置使字体正常工作,并对文档中的示例进行了一些调整。

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

我不知道为什么它的工作,我的猜测可能是 <AllowedMethod><AllowedHeader> Content-*是必要的。

如果任何人精通亚马逊 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 缓存。

文档指出,您可以将配置作为“您的 bucket 中的 cors 子资源”我认为这意味着我将使用配置在 bucket 的根目录下创建一个名为“ cors”的文件,但是这样做不起作用。最后,我必须登录到 AmazonS3管理区域,并在 bucket 的 properties对话框中添加配置。

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

在我的例子中,我没有在 CORS 配置中定义 XML 名称空间和版本。

变了

<CORSConfiguration>

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

经过一些调整,我似乎已经得到了这个工作没有查询字符串黑客。更多信息在这里: http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/RequestAndResponseBehaviorS3Origin.html#RequestS3-cors

我将要通过我的整个设置,以便很容易看到我所做的,希望这有助于其他人。

背景资料: 我正在使用一个 Rails 应用程序,它具有 asset _ sync gem,可以将资产放到 S3上,其中包括字体。

在 S3控制台中,我点击我的 bucket、属性和“编辑 cors 配置”,在这里:CORS config button

在文本区域内部,我有这样的东西:

<?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)中,我创建了一个发行版,添加了一个 Originthat 指向我的 S3 bucket adding an origin

然后添加一个默认路径的行为,以指向基于 S3的原始 I 设置。我还点击了白名单标题,添加了 Origin: adding a behavior and whitelist headers

现在发生的事情是这样的,我相信这是正确的:

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

注意,上面的域已经成功地更改,没有查询字符串黑客。

当我改变起源头,似乎总是有一个 X-Cache: Miss from cloudfront的第一个请求,然后我得到了预期的 X-Cache: Hit from cloudfront

附言。值得注意的是,当做 curl-I (大写 I)将不会显示访问控制-允许-起源头,因为它只是一个头,我做-i 使它一个 GET 和向上滚动。

我的字体被正确的服务,直到最后一次推到 Heroku... 我不知道为什么,但通配符在 CORS 允许的原点停止工作。我在 bucket 设置中将 我所有的优点和优点域添加到 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

有一个更好更简单的方法!

我个人更喜欢使用我的 DNS 子域名来解决这个问题。如果我的 CDN 是在 CDN.myawesomeapp.com 后面而不是在 sdf73n7ssa.cloudfront.net 后面,那么浏览器就不会因为跨域安全问题而抓狂和屏蔽它们。

要将子域指向您的 AWS Cloudfront 域,请转到 AWS Cloudfront 控制面板,选择 Cloudfront 发行版并将您的 CDN 子域输入到 Alternate Domain Names (CNAME)字段中。比如 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/

<ifModule mod_headers.c>


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


</ifModule>

简单解决方案

这个配置适合我。我可以列出对象,检索,更新和删除。

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

重新启动我的 Spring 启动应用程序(服务器)为我解决了这个问题。

我在 S3上正确地配置了 CORS。 Curl 用原始头部给出了正确的响应。 Safari 正确地获取了字体。 只有铬合金不愿意接受 CORS。

不确定到底是什么导致了这种行为。 一定是与 If 修改-since 有关

在 Amazon S3 CORS 配置(S3 Bucket/Permission/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 文件,但是适用于 它不适用于字体文件

您必须指定域以允许 CORS 使用@VKen 答案中表达的模式: 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 Invalidations)和它将工作。

这与字体无关,但与图像有关,这可能是一个边缘情况,但正如它发生在我身上,它也可能发生在另一个人身上。我把这个放在这里,希望它能帮到别人:

如果你处于“我已经做了他们告诉我的所有事情,但它仍然不能工作”的情况下,这可能是 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 Image 元素 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'

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

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

2021解决方案,在不危及安全的情况下允许 "*"AllowedDomains

步骤1)让 S3接受 CORS

S3桶 > 权限 > 跨来源资源共享(CORS)中,在 AllowedOrigins中添加域/域的列表。请参阅 官方文件中的示例。你只需要 GETAllowedMethods

步骤2)告诉 CloudFront 发送 CORS 头文件

在 CloudFront Action < OriginRequest Policy 中,确保选择了一个发送 originaccess-control-request-headers头文件的策略,例如 Managed-CORS-S3Origin

enter image description here

步骤3)[可选,只有当您有多个域]

关于如何在 CORS 中为 S3 + CloudFront 处理多个域,请参见 我的答案

步骤4)使 CloudFront 分发无效

祝你好运!