139

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

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

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

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

编辑:很高兴看到 S3 CORS 配置的示例。

编辑2:我找到了一个可行的解决方案,但并没有真正理解它的作用。如果有人可以提供有关配置的更详细解释以及亚马逊对配置的解释中发生的背景魔法,我们将不胜感激,就像 nzifnab 为它提供赏金一样。

4

13 回答 13

151

2014 年 9 月 10 日更新:

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


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

我的字体托管在 S3 上,但前端是 cloudfront。

我不确定它为什么起作用,我的猜测可能是<AllowedMethod> GETand<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 缓存。

于 2012-09-08T12:45:57.507 回答
102

经过一些调整后,我似乎已经让它在没有查询字符串破解的情况下工作。更多信息在这里:http ://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/RequestAndResponseBehaviorS3Origin.html#RequestS3-cors

我将完成整个设置,以便轻松查看我所做的工作,希望这对其他人有所帮助。

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

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

在 textarea 里面我有类似的东西:

<?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 的原点。我还做的是单击白名单标题并添加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==

(请注意,上面是来自云端的缺失,因为这些文件被缓存了 180 秒,但同样适用于命中)

3)使用不同的来源(但在 S3 存储桶的 CORS 上允许的来源)命中云端 -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 并向上滚动。

于 2014-08-14T10:32:22.253 回答
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更新:也添加你的

于 2014-09-14T10:43:50.157 回答
8

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

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

于 2012-09-24T18:51:40.170 回答
8

在 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 文件,但不适用于字体文件

您必须使用@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),它将起作用。

于 2018-03-01T12:56:27.800 回答
6

就我而言,我没有在 CORS 配置中定义 XML 命名空间和版本。定义那些工作。

改变了

<CORSConfiguration>

<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
于 2014-05-21T03:48:00.860 回答
5

有更好更简单的方法!

我个人更喜欢使用我的 DNS 子域来解决这个问题。如果我的 CDN 在 cdn.myawesomeapp.com 而不是 sdf73n7ssa.cloudfront.net 之后,那么浏览器就不会因为跨域安全问题而崩溃并阻止它们。

要将您的子域指向您的 AWS Cloudfront 域,请转到 AWS Cloudfront 控制面板,选择您的 Cloudfront 分配并将您的 CDN 子域输入到备用域名 (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/

于 2015-03-02T14:12:57.857 回答
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>
于 2015-08-02T15:36:12.090 回答
2

2021 解决方案,通过允许"*"进入而不会危及安全AllowedDomains

步骤 1) 允许 S3 接收 CORS

S3 存储桶> 权限 > 跨域资源共享 (CORS) 中,将您的域列表添加到AllowedOrigins. 有关示例,请参见官方文档。你只GET需要AllowedMethods.

步骤 2) 告诉 CloudFront 通过 CORS 标头发送

在您的 CloudFront Behavior < Origin Request Policy 中,确保您选择了发送originaccess-control-request-headers标头的策略,例如Managed-CORS-S3Origin.

在此处输入图像描述

步骤 3) [可选,仅当您拥有多个域时]

请参阅我的这个答案,了解如何在 CORS 中为 S3+CloudFront 处理多个域。

步骤 4) 使您的 CloudFront 分配无效

祝你好运!

于 2021-05-19T20:33:29.563 回答
1
<ifModule mod_headers.c>

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

</ifModule>

简单的解决方案

于 2015-03-08T15:56:17.953 回答
1

这与字体无关,而是与图像有关,这可能是一种边缘情况,但就像发生在我身上一样,它可能会发生在另一个人身上。我将把它留在这里,希望它能帮助某人:

如果您处于“我已经完成了他们告诉的所有操作,但仍然无法正常工作”的情况,这可能是 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 中却不行。如果您要从简单标记和 js Image 元素 src访问远程图像路径<img src="http://my.remote.server.com/images/cat.png">如下所示:

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>
于 2019-10-02T10:03:49.397 回答
0

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

我在 S3 上正确配置了 CORS。curl 使用原始标头给出了正确的响应。Safari 正在正确获取字体。只有 chrome 不愿意接受 CORS。

不确定究竟是什么导致了这种行为。必须与If-modified-since有关

于 2016-10-10T11:29:46.280 回答
-1

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

于 2012-09-02T05:59:03.183 回答