从 AWS Cloudfront 提供服务时发出加载 webfonts
Issue loading webfonts when served from AWS Cloudfront
所以,这是我的难题!在过去的三天里,我一直在努力让 Cloudfront 与我的 nginx 服务器配合得很好……阅读了无数 Whosebug posts 和博客文章……搜索了互联网,但我仍然被围绕 cross-domain 关于 Cloudfront 服务字体的访问策略。我将 post 我的完整设置,希望有更多专业知识的人可以帮助我弄清楚发生了什么。将来,我希望这个 post 能为许多面临类似问题的人服务。 这里...
Nginx 配置:
我有一个具有以下服务器块配置的 nginx 网络服务器。 (...为简洁起见被截断)
server {
server_name example.com www.example.com;
root /var/www/example.com/html;
index index.html index.htm;
location / {
try_files $uri $uri/ =404;
}
location /assets {
autoindex on;
}
# Media
location ~* \.(jpe?g|gif|png|ico|cur|gz|svgz?|mp4|ogg|ogv|webm|htc|webp)$ {
expires 1M;
access_log off;
add_header Cache-Control public;
}
# Fonts
location ~* \.(eot|ttf|woff|woff2|svg)$ {
expires 365d;
access_log off;
add_header Cache-Control public;
add_header Access-Control-Allow-Origin example.com;
// Have also tried setting the "Access-Control-Allow-Origin" header to "*", but I'd prefer not to do this for security reasons.
}
}
仅供参考:我想提供并卸载到 CloudFront 的所有网站文件都在我的虚拟主机的 /assets
目录中。 (即http://example.com/assets/.。)
CloudFront:
我使用以下设置创建了一个新的 CloudFront 分配:
注意:我没有使用 S3 来托管我的网站文件和资产。
一般:
- 备用域名 (CNAME):static.example.com
- 默认根Object:index.html
起源:
- 源域名:example.com
- 原始路径:(留空)
- 源 SSL 协议:TLSv1.2、TLSv1.1、TLSv1
- 源协议策略:仅限 HTTP
- HTTP 端口:80
- HTTPS 端口:443
- 来源自定义 Headers:(none)
行为:
- 路径模式:默认()*
- 查看器协议策略:HTTP 和 HTTPS
- 允许的 HTTP 方法:GET、HEAD
- 缓存的 HTTP 方法:GET、HEAD(默认缓存)
- 转发Headers:白名单
- Access-Control-Allow-Origin
- Object缓存:使用原始缓存Headers
- 转发查询字符串:否(改进缓存)
- 自动压缩 Objects: 是
DNS 设置:
我的区域文件的一部分...
example.com. 1800 IN A 12.34.567.890 //faked IP here for privacy reasons
www.example.com. 1800 IN CNAME example.com.
static.example.com. 1800 IN CNAME kg72kgf83nhfy3.cloudfront.net. //faked CloudFront dist. domain name here for privacy reasons
发生了什么事?为什么不行?
因此,CloudFront 会处理和部署我的分发,我假设从我的 '/assets/..'[ 中提取资产=156=]网页目录。所有 src
、href
和 CSS url()
引用都指向 http://static.example.com in my current HTML and CSS documents, including all font-face
references. After the distribution is deployed, I hit my site http://example.com 在浏览器中。
似乎所有静态站点资产都从 CloudFront 正确提供,带有适当的缓存 headers,如我的 nginx 配置中所定义...EXCEPT...网络字体。我在页面上缺少字体,并且在我的浏览器控制台中收到 cross-domain 访问策略错误消息。
Headers—
一张图片,供参考(ping我的服务器时):
curl -I "http://example.com/assets/images/image1.png"
HTTP/1.1 200 OK
Server: nginx/1.6.3
Date: Sun, 15 May 2016 02:09:25 GMT
Content-Type: image/png
Content-Length: 194665
Last-Modified: Sun, 15 May 2016 01:52:35 GMT
Connection: keep-alive
ETag: "5737d663-2f869"
Expires: Tue, 14 Jun 2016 02:09:25 GMT
Cache-Control: max-age=2592000
Cache-Control: public
Accept-Ranges: bytes
一种字体(当 ping 我的服务器时):
curl -I "http://example.com/assets/fonts/webfont.woff"
HTTP/1.1 200 OK
Server: nginx/1.6.3
Date: Sun, 15 May 2016 02:10:29 GMT
Content-Type: application/font-woff
Content-Length: 8752
Last-Modified: Sun, 15 May 2016 01:51:55 GMT
Connection: keep-alive
Vary: Accept-Encoding
ETag: "5737d63b-2230"
Expires: Mon, 15 May 2017 02:10:29 GMT
Cache-Control: max-age=31536000
Cache-Control: public
Access-Control-Allow-Origin: example.com
Accept-Ranges: bytes
相同图像(从 CloudFront 请求时):
curl -I "http://static.example.com/assets/images/image1.png"
HTTP/1.1 200 OK
Content-Type: image/png
Content-Length: 194665
Connection: keep-alive
Server: nginx/1.6.3
Date: Sun, 15 May 2016 02:39:16 GMT
Last-Modified: Sun, 15 May 2016 01:52:35 GMT
ETag: "5737d663-2f869"
Expires: Tue, 14 Jun 2016 02:39:16 GMT
Cache-Control: max-age=2592000
Cache-Control: public
Accept-Ranges: bytes
X-Cache: Miss from cloudfront
Via: 1.1 lots_of_random_characters_i_dont_know_if_should_share_here.cloudfront.net (CloudFront)
X-Amz-Cf-Id: lSM1plINYENbYycBn424LJ2wdtDhS3CpqAFiDSoxQDEctP_WM09bUQ==
相同字体(从 CloudFront 请求时):
curl -I "http://static.example.com/assets/fonts/webfont.woff"
HTTP/1.1 200 OK
Content-Type: application/font-woff
Content-Length: 8752
Connection: keep-alive
Server: nginx/1.6.3
Date: Sun, 15 May 2016 02:41:00 GMT
Last-Modified: Sun, 15 May 2016 01:51:55 GMT
ETag: "5737d63b-2230"
Expires: Mon, 15 May 2017 02:41:00 GMT
Cache-Control: max-age=31536000
Cache-Control: public
Access-Control-Allow-Origin: example.com
Accept-Ranges: bytes
Vary: Accept-Encoding
X-Cache: Miss from cloudfront
Via: 1.1 lots_of_random_characters_i_dont_know_if_should_share_here.cloudfront.net (CloudFront)
X-Amz-Cf-Id: vNfiyurS8pjosofnpLNSrnZuaGFg0V4xIs4ySCm05NKDMZ_PozhuOg==
在 http://example.com 加载我的网站,一切似乎都正常(即图像)EXCEPT 网络字体。检查浏览器控制台为每种字体输出以下消息:
Font from origin 'http://static.example.com' has been blocked from loading by Cross-Origin Resource Sharing policy: The 'Access-Control-Allow-Origin' header contains the invalid value 'example.com'. Origin 'http://example.com' is therefore not allowed access.
那么,有人有什么想法吗??我会 非常 感谢 help/input。我是一名正在努力学习的年轻 Web 开发人员。
谢谢! :)
–凯尔
脚注:
- One of many blog posts我已经关注了,但还没有成功。
- 我的计划是将散列查询字符串附加到每个文件的末尾(即
//static.example.com/assets/images/image.png?622c6911
)以使 CloudFront 缓存无效。这样我就不必总是 re-upload 名称更改的新资产...我可以简单地控制 HTML 的失效并在我希望 CloudFront 请求最新版本时将新的查询字符串附加到资产来自我的网络服务器 Origin 的那个文件。
- 我最终会为我的网站购买 SSL 证书,所以我希望流量能够同时支持 HTTP 和 HTTPS 请求。
解释在这里:
The 'Access-Control-Allow-Origin' header contains the invalid value 'example.com'. Origin 'http://example.com' is therefore not allowed access.
来源是 http://example.com
... 不是 example.com
。您的回复 header 的值有误。根据定义,来源是方案 + 主机名 + 端口(标准端口上的 http 和 https 省略了隐式端口 80 和 443)。
当请求不受 cross-origin 规则的约束时,例如图像的情况,浏览器将忽略 Web 服务器上的这种错误配置。对于字体,您正在撞墙,因为值格式不正确。
add_header Access-Control-Allow-Origin example.com;
这是你问题的根源。您需要在 Origin:
header 中使用浏览器发送的相同来源进行响应,假设该来源确实有效并且应该被允许。我不是 nginx 专家,根据 this answer,您可以使用正则表达式验证传入来源,并相应地设置响应:
if ($http_origin ~* "^https?://.*example\.com$" ) {
add_header Access-Control-Allow-Origin $http_origin;
}
不熟悉 nginx 正则表达式的怪癖,我的有点宽容,但你明白了。
在此之前,我们需要修复 CloudFront 缓存行为。
Forward Headers: Whitelist
Access-Control-Allow-Origin
那不是一个请求 header...那是一个响应 header,所以将它列入白名单实际上并没有做任何事情。
相反,您需要将 Origin
header 列入白名单,以便 CloudFront 将其转发到 Web 服务器,以便服务器可以使用 [=] 中的相同值进行响应16=],如上图所示。
Access-Control-Request-Headers
和 Access-Control-Request-Method
也应该列入白名单,但对于 GET
请求,我不知道它们是否重要。
除了 GET
和 HEAD
.
之外,您还应该修改允许的方法以包括 OPTIONS
奖金material:
My plan is to append hashed query strings to the end of every file (ie. //static.example.com/assets/images/image.png?622c6911) to invalidate the CloudFront cache.
在这种情况下,您需要将 Forward Query Strings
设置为 Yes
。
CloudFront 根据它实际发送到服务器的内容缓存 objects。如果查询字符串未转发到源,则附加查询字符串只会使 浏览器 缓存无效,而不会使 CloudFront 缓存无效。是的,如果查询字符串旨在用于 cache-busting CloudFront,即使您的服务器不需要或不需要查询字符串,您也需要启用此功能。这就是为什么不转发它们 "improves caching." CloudFront 将 "improved" 在确定它是否已经具有 object.
的缓存版本时完全忽略它们
此外,请注意 Via
header 不包含敏感信息,X-Amz-Cf-Id
.
也不包含敏感信息
所以,这是我的难题!在过去的三天里,我一直在努力让 Cloudfront 与我的 nginx 服务器配合得很好……阅读了无数 Whosebug posts 和博客文章……搜索了互联网,但我仍然被围绕 cross-domain 关于 Cloudfront 服务字体的访问策略。我将 post 我的完整设置,希望有更多专业知识的人可以帮助我弄清楚发生了什么。将来,我希望这个 post 能为许多面临类似问题的人服务。 这里...
Nginx 配置:
我有一个具有以下服务器块配置的 nginx 网络服务器。 (...为简洁起见被截断)
server {
server_name example.com www.example.com;
root /var/www/example.com/html;
index index.html index.htm;
location / {
try_files $uri $uri/ =404;
}
location /assets {
autoindex on;
}
# Media
location ~* \.(jpe?g|gif|png|ico|cur|gz|svgz?|mp4|ogg|ogv|webm|htc|webp)$ {
expires 1M;
access_log off;
add_header Cache-Control public;
}
# Fonts
location ~* \.(eot|ttf|woff|woff2|svg)$ {
expires 365d;
access_log off;
add_header Cache-Control public;
add_header Access-Control-Allow-Origin example.com;
// Have also tried setting the "Access-Control-Allow-Origin" header to "*", but I'd prefer not to do this for security reasons.
}
}
仅供参考:我想提供并卸载到 CloudFront 的所有网站文件都在我的虚拟主机的 /assets
目录中。 (即http://example.com/assets/.。)
CloudFront:
我使用以下设置创建了一个新的 CloudFront 分配:
注意:我没有使用 S3 来托管我的网站文件和资产。
一般:
- 备用域名 (CNAME):static.example.com
- 默认根Object:index.html
起源:
- 源域名:example.com
- 原始路径:(留空)
- 源 SSL 协议:TLSv1.2、TLSv1.1、TLSv1
- 源协议策略:仅限 HTTP
- HTTP 端口:80
- HTTPS 端口:443
- 来源自定义 Headers:(none)
行为:
- 路径模式:默认()*
- 查看器协议策略:HTTP 和 HTTPS
- 允许的 HTTP 方法:GET、HEAD
- 缓存的 HTTP 方法:GET、HEAD(默认缓存)
- 转发Headers:白名单
- Access-Control-Allow-Origin
- Object缓存:使用原始缓存Headers
- 转发查询字符串:否(改进缓存)
- 自动压缩 Objects: 是
DNS 设置:
我的区域文件的一部分...
example.com. 1800 IN A 12.34.567.890 //faked IP here for privacy reasons
www.example.com. 1800 IN CNAME example.com.
static.example.com. 1800 IN CNAME kg72kgf83nhfy3.cloudfront.net. //faked CloudFront dist. domain name here for privacy reasons
发生了什么事?为什么不行?
因此,CloudFront 会处理和部署我的分发,我假设从我的 '/assets/..'[ 中提取资产=156=]网页目录。所有 src
、href
和 CSS url()
引用都指向 http://static.example.com in my current HTML and CSS documents, including all font-face
references. After the distribution is deployed, I hit my site http://example.com 在浏览器中。
似乎所有静态站点资产都从 CloudFront 正确提供,带有适当的缓存 headers,如我的 nginx 配置中所定义...EXCEPT...网络字体。我在页面上缺少字体,并且在我的浏览器控制台中收到 cross-domain 访问策略错误消息。
Headers—
一张图片,供参考(ping我的服务器时):
curl -I "http://example.com/assets/images/image1.png" HTTP/1.1 200 OK Server: nginx/1.6.3 Date: Sun, 15 May 2016 02:09:25 GMT Content-Type: image/png Content-Length: 194665 Last-Modified: Sun, 15 May 2016 01:52:35 GMT Connection: keep-alive ETag: "5737d663-2f869" Expires: Tue, 14 Jun 2016 02:09:25 GMT Cache-Control: max-age=2592000 Cache-Control: public Accept-Ranges: bytes
一种字体(当 ping 我的服务器时):
curl -I "http://example.com/assets/fonts/webfont.woff" HTTP/1.1 200 OK Server: nginx/1.6.3 Date: Sun, 15 May 2016 02:10:29 GMT Content-Type: application/font-woff Content-Length: 8752 Last-Modified: Sun, 15 May 2016 01:51:55 GMT Connection: keep-alive Vary: Accept-Encoding ETag: "5737d63b-2230" Expires: Mon, 15 May 2017 02:10:29 GMT Cache-Control: max-age=31536000 Cache-Control: public Access-Control-Allow-Origin: example.com Accept-Ranges: bytes
相同图像(从 CloudFront 请求时):
curl -I "http://static.example.com/assets/images/image1.png" HTTP/1.1 200 OK Content-Type: image/png Content-Length: 194665 Connection: keep-alive Server: nginx/1.6.3 Date: Sun, 15 May 2016 02:39:16 GMT Last-Modified: Sun, 15 May 2016 01:52:35 GMT ETag: "5737d663-2f869" Expires: Tue, 14 Jun 2016 02:39:16 GMT Cache-Control: max-age=2592000 Cache-Control: public Accept-Ranges: bytes X-Cache: Miss from cloudfront Via: 1.1 lots_of_random_characters_i_dont_know_if_should_share_here.cloudfront.net (CloudFront) X-Amz-Cf-Id: lSM1plINYENbYycBn424LJ2wdtDhS3CpqAFiDSoxQDEctP_WM09bUQ==
相同字体(从 CloudFront 请求时):
curl -I "http://static.example.com/assets/fonts/webfont.woff" HTTP/1.1 200 OK Content-Type: application/font-woff Content-Length: 8752 Connection: keep-alive Server: nginx/1.6.3 Date: Sun, 15 May 2016 02:41:00 GMT Last-Modified: Sun, 15 May 2016 01:51:55 GMT ETag: "5737d63b-2230" Expires: Mon, 15 May 2017 02:41:00 GMT Cache-Control: max-age=31536000 Cache-Control: public Access-Control-Allow-Origin: example.com Accept-Ranges: bytes Vary: Accept-Encoding X-Cache: Miss from cloudfront Via: 1.1 lots_of_random_characters_i_dont_know_if_should_share_here.cloudfront.net (CloudFront) X-Amz-Cf-Id: vNfiyurS8pjosofnpLNSrnZuaGFg0V4xIs4ySCm05NKDMZ_PozhuOg==
在 http://example.com 加载我的网站,一切似乎都正常(即图像)EXCEPT 网络字体。检查浏览器控制台为每种字体输出以下消息:
Font from origin 'http://static.example.com' has been blocked from loading by Cross-Origin Resource Sharing policy: The 'Access-Control-Allow-Origin' header contains the invalid value 'example.com'. Origin 'http://example.com' is therefore not allowed access.
那么,有人有什么想法吗??我会 非常 感谢 help/input。我是一名正在努力学习的年轻 Web 开发人员。
谢谢! :)
–凯尔
脚注:
- One of many blog posts我已经关注了,但还没有成功。
- 我的计划是将散列查询字符串附加到每个文件的末尾(即
//static.example.com/assets/images/image.png?622c6911
)以使 CloudFront 缓存无效。这样我就不必总是 re-upload 名称更改的新资产...我可以简单地控制 HTML 的失效并在我希望 CloudFront 请求最新版本时将新的查询字符串附加到资产来自我的网络服务器 Origin 的那个文件。 - 我最终会为我的网站购买 SSL 证书,所以我希望流量能够同时支持 HTTP 和 HTTPS 请求。
解释在这里:
The 'Access-Control-Allow-Origin' header contains the invalid value 'example.com'. Origin 'http://example.com' is therefore not allowed access.
来源是 http://example.com
... 不是 example.com
。您的回复 header 的值有误。根据定义,来源是方案 + 主机名 + 端口(标准端口上的 http 和 https 省略了隐式端口 80 和 443)。
当请求不受 cross-origin 规则的约束时,例如图像的情况,浏览器将忽略 Web 服务器上的这种错误配置。对于字体,您正在撞墙,因为值格式不正确。
add_header Access-Control-Allow-Origin example.com;
这是你问题的根源。您需要在 Origin:
header 中使用浏览器发送的相同来源进行响应,假设该来源确实有效并且应该被允许。我不是 nginx 专家,根据 this answer,您可以使用正则表达式验证传入来源,并相应地设置响应:
if ($http_origin ~* "^https?://.*example\.com$" ) {
add_header Access-Control-Allow-Origin $http_origin;
}
不熟悉 nginx 正则表达式的怪癖,我的有点宽容,但你明白了。
在此之前,我们需要修复 CloudFront 缓存行为。
Forward Headers: Whitelist
Access-Control-Allow-Origin
那不是一个请求 header...那是一个响应 header,所以将它列入白名单实际上并没有做任何事情。
相反,您需要将 Origin
header 列入白名单,以便 CloudFront 将其转发到 Web 服务器,以便服务器可以使用 [=] 中的相同值进行响应16=],如上图所示。
Access-Control-Request-Headers
和 Access-Control-Request-Method
也应该列入白名单,但对于 GET
请求,我不知道它们是否重要。
除了 GET
和 HEAD
.
OPTIONS
奖金material:
My plan is to append hashed query strings to the end of every file (ie. //static.example.com/assets/images/image.png?622c6911) to invalidate the CloudFront cache.
在这种情况下,您需要将 Forward Query Strings
设置为 Yes
。
CloudFront 根据它实际发送到服务器的内容缓存 objects。如果查询字符串未转发到源,则附加查询字符串只会使 浏览器 缓存无效,而不会使 CloudFront 缓存无效。是的,如果查询字符串旨在用于 cache-busting CloudFront,即使您的服务器不需要或不需要查询字符串,您也需要启用此功能。这就是为什么不转发它们 "improves caching." CloudFront 将 "improved" 在确定它是否已经具有 object.
的缓存版本时完全忽略它们此外,请注意 Via
header 不包含敏感信息,X-Amz-Cf-Id
.