#### **内容简介**
在这篇博客文章中,您将进一步了解 [Amazon CloudFront](https://aws.amazon.com/cn/cloudfront/?trk=cndc-detail) 的功能,这些功能可以帮助您根据需求定义内容交付方式,提高服务性能及可用性。
以下我们将从配置和经典需求中,带您了解如何更好的使用 CloudFront 进行加速设置。
一. 构建测试动态源站
二. 源站设置
三. 路径匹配及缓存策略
四. 回源请求及响应头策略
五. 错误响应设置
六. 缓存失效
通过本指南,您将学会如何利用 CloudFront 进行更多的配置构建,以符合实际业务的需求。
在小指南一中的 S3 静态源站基础上,我们将构建了一个动静兼具的最小源站架构。
架构图:
![1.png](https://dev-media.amazoncloud.cn/e1fdcf43608a4940ad573d4eb48ac3ce_1.png "1.png")
#### **构建测试动态源站及展示页面**
在小指南一中,我们已经基于 S3 构建了一个最小架构的静态源站,为了更好的配合以下设置,接下来我们需要构建一个响应动态内容的源站,为了方便演示,此处以一个 echo-server 的 Docker 镜像,创建一个 httpecho 的容器让它能够把我们通过 http 访问服务器的请求头都提取出来作为 http 响应给我们的浏览器。
首先启用一个 t2.micro 的 EC2,使用 Amazon Linux2 AMI 启动。
在此 EC2 上安装 Docker,参考 https\://docs.aws.amazon.com/zh_cn/AmazonECS/latest/developerguide/docker-basics.html?trk=cndc-detail。
具体 Linux 命令如下:
1\. 安装 docker
```
sudo yum update -y
sudo amazon-linux-extras install docker
```
2\. 赋予 ec2-user 用户 docker 启动的 linux 权限
```
sudo usermod -a -G docker ec2-user
```
<!--StartFragment-->
3\. 退出当前 ssh session 以使权限生效
```
logout
```
4\. 使用 ec2-user 再次 login 检查 docker 信息
```
sudo service docker start
docker info | grep Ver
```
输出如下即为 docker 安装成功:
```
Server Version: 20.10.7
Cgroup Version: 1
Kernel Version: 4.14.47-64.38.amzn2.x86_64
```
<!--StartFragment-->
5\. 运行 echo-server docker image,监听 TCP 1028 端口
```
docker run -d --name httpecho -p 1028:8080 jmalloc/echo-server httpecho
```
6\. curl 检查本地服务
```
curl 127.0.0.1:1028
```
输出如下即表示服务正常。该输出表示 echo-server 服务器收到 curl 送来的 http 请求,内容非常简单:
```
Request served by 16e51706efbe
HTTP/1.1 GET /
Host: 127.0.0.1:1028
User-Agent: curl/7.79.1
Accept: /
```
接下来,为了更便于展示效果,我们将使用一个简单的 HTML 页面,将静态元素和动态元素进行结合,您可以先将以下 html 代码保存为 index.html 的并上传至 S3 当中:
```
<!DOCTYPE html>
<html lang="en">
<body>
<table border="1" width="600px" height="800px">
<thead>
<tr><td height="50px"><h1>CloudFront Lab</h1></td></tr>
</thead>
<tfoot>
<tr><td height="50px">AWS Edge Services - Demo</td></tr>
</tfoot>
<tbody>
<tr><td height="50px">Response sent by API</td></tr>
</tbody>
<tbody>
<tr><td height="300px"> <img src='../infra.png' style="width:100%; height:100%;"></img></td></tr>
</tbody>
<tbody>
<tr><td height="650px"> <iframe src='../api' style="width:100%; height:100%;"></iframe></td></tr>
</tbody>
</table>
</body>
</html>
```
#### **路径匹配及缓存策略**
配置缓存策略之前,我们需要先了解下 CloudFront 如何根据行为(Behavior)中的路径识别,来找到对应的策略,配置路径匹配(Path Pattern)时,我们需要遵循以下的规则:
* 按序执行,规则序号越小,优先级越高
* \* 匹配 0 个或多个字符
* 大小写敏感
* ?匹配 1 个字符
* 不支持正则表达式
同时,为了让缓存结果符合预期,我们也需要了解缓存策略(Cache Policy)中的 TTL 设置以及缓存键值(Cache Key)设置的工作方式:
关于 TTL 设置,此处以下图的设置进行举例说明:
![2.png](https://dev-media.amazoncloud.cn/b286d3377bfe42e986933f62d63827c7_2.png "2.png")
CloudFront 将根据源服务器响应的 cache-control 或 expire,结合缓存策略中的 TTL 设置决定缓存多长时间,此处举三个例子来说明最终的效果:
* 源站响应了 Cache-Control: max-age=3600,由于 3600 落在了 TTL 最大值和最小值 1 – 86400 的区间,则 CloudFront 将缓存 3600 秒
* 源站响应了 Cache-Control: max-age=99999,由于 99999 超出了 TTL 最大值 86400,则 CloudFront 将缓存 86400 秒
* 源站未响应 cache-control或expire,由于默认 TTL(Default TTL)设置为 60 秒,则 CloudFront 将缓存 60 秒
关于缓存键值的设置,CloudFront 可识别以下三种请求元素,进而将指定元素作为缓存键值进行缓存,分别为:请求头 / 参数 / Cookie
![3.png](https://dev-media.amazoncloud.cn/14ff5975e77042f0bd9621d5a5d5ff28_3.png "3.png")
除了用户携带的请求头可作为缓存键值以外,CloudFront 还内置了诸多供用户使用的请求头,用于识别用户的 设备类型 / 地理位置 等,具体可参考 – 添加 CloudFront 请求标头(https\://docs.aws.amazon.com/zh_cn/AmazonCloudFront/latest/DeveloperGuide/adding-cloudfront-headers.html?trk=cndc-detail), 您可根据具体业务需求,结合该头部信息进行缓存内容的区分。
另外,当服务中启用了压缩支持(compression support)时,CloudFront 还将根据不同的压缩格式分开进行缓存,并根据请求端发送的 accept-encoding 头部进行相应的内容返回:
![4.png](https://dev-media.amazoncloud.cn/2150fa7a2c064569a186b02638675fb9_4.png "4.png")
关于缓存键值的设置,为了保证实际使用 CloudFront 时维持一个良好且健康的缓存命中率,我们需要遵循“**非必要不添加缓存键值**”的原则,以下为一个常用的缓存键值场景举例:
页面中的某个静态元素,需要根据用户所携带的 v 参数,来作为缓存版本号识别,进行缓存区分,针对这种需求,我们可以这么设置缓存键值:
![5.png](https://dev-media.amazoncloud.cn/4cee3b9c9b614387baa138fd3e8fb211_5.png "5.png")
结合上述的原理以及我们准备好的源站环境,以下两个例子将解释网站中常用的两种场景——
**场景 1** : 网站中以 webp 结尾的路径需要缓存,且需要根据参数v进行缓存版本区分,缓存时间强制设置为 86400
根据场景需求我们可以进行以下设置:
路径匹配:
![6.png](https://dev-media.amazoncloud.cn/c89613473279457d87edf3f07875764f_6.png "6.png")
缓存 TTL 以及缓存键值设置,我们可以在 Policies – Cache 中,或是 Edit Behavior 页面中自定义构建缓存方式:
![7.png](https://dev-media.amazoncloud.cn/93f009f5fbd0422a9f8e93a939fabd8a_7.png "7.png")
缓存 TTL 及缓存键值设置,设置完毕后保存:
![8.png](https://dev-media.amazoncloud.cn/d5ce87aff25e413792226cca53a4274f_8.png "8.png")
选中刚才创建的 Cache Policy 并保存:
![9.png](https://dev-media.amazoncloud.cn/787b7d5fd100446a866f81446c348db0_9.png "9.png")
**场景 2** :网站中的/api 路径,回源 EC2,且不缓存
在小指南一的基础上,我们的设置已经有了 S3 的源站,我们先创建 EC2 源,选中刚才创建的 EC2:
![9999.png](https://dev-media.amazoncloud.cn/fa0633706e3f4413ab12a0e996556dfd_9999.png "9999.png")
注:在此实验中,EC2 echoserver 监听的端口为 1028,您在创建 EC2 源时需注意指定端口,启用 HTTP/HTTPS,HTTPS 443 端口保持不变,为接下来的实验做准备。
我们可以设置以下的路径匹配,缓存策略则可以使用 CloudFront 托管的缓存策略 – Managed-CachingDisabled,具体设置如下:
![10.png](https://dev-media.amazoncloud.cn/31318e9f6389493e966afeb9529ee3b9_10.png "10.png")
同理,我们也将 index.html 按照 S3 为源站 / CachingDisable 的方式进行设置。
![11.png](https://dev-media.amazoncloud.cn/7480bc46b9d6411186d76bf370a29a13_11.png "11.png")
效果测试:
在测试实际效果中,我们可以利用到 CloudFront 原生的 X-Cache 响应头,来浏览器中观察缓存状态是否符合预期。
使用 HTTP 方法访问您的 index.html 页面(如 http\://xxx.xxx.com/index.html), 在重复刷新页面后,可以看到 infra.png 此请求的 X-Cache 状态为Hit。
![12.png](https://dev-media.amazoncloud.cn/a2e3a1452f23447abe8bffc9b6b1e71d_12.png "12.png")
而/api 路径由于缓存策略设置为不缓存,多次刷新后状态仍然为 Miss。
![13.png](https://dev-media.amazoncloud.cn/57333139a639483c8af0b3658f24e934_13.png "13.png")
#### **源组设置**
尽管有许多不同的方法可以提高网站的可用性,例如如果承载网站的原始服务器在亚马逊云中,则使用弹性负载平衡和多可用区,但 CloudFront 可为您的网站带来了更高的可用性。
网站可用性最常受到网络故障/服务器中断或内容不可用的影响,但有许多因素可能会影响网站的可用性。例如,网站停机可能是由于意外的硬件故障造成的。您可以通过使所有组件完全冗余来减轻这种类型的风险。在 CloudFront 的源设置中,提供了源组(Origin Group)的功能,您可以为源服务器端点提供多个冗余,避免由于一个源站故障或内容不可用而引起业务中断。
![14.png](https://dev-media.amazoncloud.cn/e8e042fe14d049a0a935e43d4f25a1d5_14.png "14.png")
注:如果您使用的源站为非 Amazon 资源,如其他云服务计算资源,建议您在设置源站时启用源护盾(Origin Shield)功能,充分利用骨干网络,以保持业务的最佳性能以及可用性。
如以上截图,您在实际配置时,如需设置源组,则需要先设置出至少 2 个及以上的源,方可进行源组的设置,且您可灵活的指定源之间的主备关系,且根据源所响应的状态码,对满足特定状态码的请求进行自动宕切(Failover)。
以下我们举个例子,当访问的对象在 S3 上不存在时,CF 自动 Failover 到备用源站 EC2 去取内容:
![15.png](https://dev-media.amazoncloud.cn/167fa333f0d24499ad951ac54f524b7a_15.png "15.png")
创建完 Origin Group 后,在 Behavior 中设置一个测试用的行为,并将上述创建的源组应用到该行为中:
![16.png](https://dev-media.amazoncloud.cn/444e347491c242c4a007e0bf445cf9bc_16.png "16.png")
浏览器测试效果:
\*由于 EC2 只启用了 HTTP,请使用 HTTP 访问测试,而非 HTTPS。
![17.png](https://dev-media.amazoncloud.cn/4f2784c11d3045f5b0206eb03941f1a5_17.png "17.png")
我们可以看到当访问不存在的内容时,页面显示的不是主源上 S3 的报错信息,而是可以自动由备源 EC2 拿到内容,证明设置成功。
#### **回源请求及响应头策略**
在使用 CloudFront 为页面业务进行加速时,您同样可以决定回源时,CloudFront 应携带哪些必要信息回源,以及响应时在 CloudFront 设置相应的响应头策略,和缓存策略类似,您可以在 CloudFront 源请求策略(Origin Request Policy)中指定需要携带回源的请求头 / 参数 / Cookie,同时,您也可以灵活的制定响应头的策略,对指定的响应头进行增删改的操作,为了更好的理解,以下为一个应用案例——
因业务需求,我们需要在 CloudFront 上实现以下三个策略:
* 源站部署并监听了多个 Hostname,CloudFront 需携带用户请求的 Host 头供源站进行区分;
* 业务方需要 CloudFront 携带用户的国家信息回源,供业务方进行信息收集并统计;
* 在响应头中自定义响应头 x-cdn: CloudFront。
根据上述需求,您可以进行以下的相关设置:
* 设置源请求策略携带 Host 和 CloudFront 内置的地理位置信息头
![18.png](https://dev-media.amazoncloud.cn/d8826443e72f436fbff273b17bbece83_18.png "18.png")
* 自定义设置响应头策略
![19.png](https://dev-media.amazoncloud.cn/5eb987f622e64423b0fecc9c6b7f6409_19.png "19.png")
创建完毕后在行为路径“**/api**”中进行应用并部署:
![20.png](https://dev-media.amazoncloud.cn/070c9ae565e14e74a1c3a2fb32013f30_20.png "20.png")
效果测试:
利用到实验环境中的 echo server 响应内容为用户请求头的特性,我们可以很好的观察到配置的效果。
在部署上述请求头和响应头逻辑之前,我们可以看到该请求请求头携带回源的 Host 为 EC2 域名,响应头不携带 CORS 信息:
![21.png](https://dev-media.amazoncloud.cn/5ba50c37ece94c25a1c44ed7b07d0a04_21.png "21.png")
部署完逻辑后进行对比,我们可以看到用户请求的 host 信息已成功被携带回源,并且请求头中已携带了用户地理位置信息,响应头中也具备了我们自定义的响应头信息:
![22.png](https://dev-media.amazoncloud.cn/bef659aec04e4cf481cc7a8da1f46619_22.png "22.png")
\*在上面的测试结果我们可以看到一个有意思的现象,即 UA 为 [Amazon CloudFront](https://aws.amazon.com/cn/cloudfront/?trk=cndc-detail),这是因为在制定 Origin Policy 时,我们并未指定携带 UA 回源,在实际应用中,源服务往往需要根据请求头获取更多用户的请求特征,您可根据您的需要制定 CloudFront 应该携带哪些请求元素回源。
#### **定制错误响应**
在使用 CloudFront 进行内容分发时,我们可能会遇到 文件不存在 / 源服务器维护 / 源服务超时 等情况,导致客户端拿到错误响应或是源服务收到过多的错误请求,为了更好的缓解这种情况,CloudFront 可自定义错误响应码的缓存时间以及响应内容,以缓解源站持续收到触发错误响应码的请求,以及更友好的用户错误页面。
在这我们举例个场景,业务方需要针对源服务响应的 502 响应码进行 10 秒缓存,并且响应自定义的报错页面,我们可进行以下设置,来实现上述需求:
创建一个 custom error response
![23.png](https://dev-media.amazoncloud.cn/14a4c6bf530b43308f374ba2b12d75f4_23.png "23.png")
进行如下设置,指定 502 的 10 秒缓存时间,并且设置 sorry page 的路径,并进行 200 响应。
![24.png](https://dev-media.amazoncloud.cn/e95b12cf0cfd4d578a994213b3928f78_24.png "24.png")
这边提供了一段简单的 html 文本页面:
```
<!DOCTYPE html>
<html>
<head>
<title>Welcome to CloudFront!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Sorry, Your content is not available!</h1>
</body>
</html>
```
我们将该 html 上传至 S3 源站中作为错误页面进行展示:
![25.png](https://dev-media.amazoncloud.cn/2be332b1af1c4a4ab02c77c18c560480_25.png "25.png")
上述操作完毕后,我们可以开始测试效果,由于部署 EC2 时,我们未开启 443 端口以及部署 HTTPS 证书,此时如果使用 HTTPS 访问 CloudFront,当 CloudFront 尝试用 HTTPS 回源 EC2 时,请求将会超时并产生 502 错误。
利用这个机制我们可以模拟源服务 502 的情况,使用 HTTPS 进行对 index.html 访问,未部署定制化错误响应前,我们可以看到以下效果:
![26.png](https://dev-media.amazoncloud.cn/8d7e79f2d0fd4aed8cda3e344fc729cd_26.png "26.png")
部署定制化错误响应后:
![27.png](https://dev-media.amazoncloud.cn/0c4c0dbccdf847bba9e97720880c0a1b_27.png "27.png")
#### **缓存失效**
在实际业务中,您可能会遇到某些场景需要进行资源变更同时需要进行缓存失效,在 CloudFront Distribution 配置界面,您可以找到缓存失效的入口并进行缓存失效的动作,在确保源资源变更后,您方可在 CloudFront 上进行缓存失效的动作。
![28.png](https://dev-media.amazoncloud.cn/747b110b1bb645949b9cdf48c3c9f65e_28.png "28.png")
接下来,我们使用构建好的环境来进行缓存刷新的测试,访问/index.html,直至静态内容呈现 Hit 状态,如下图所示:
![29.png](https://dev-media.amazoncloud.cn/e5ee3f1537b54d078fbd27fb71ace75b_29.png "29.png")
下一步,在 CloudFront 失效界面,添加需要失效缓存的 URL path:
![30.png](https://dev-media.amazoncloud.cn/96327977a5ba43e5964f78acc880326b_30.png "30.png")
![31.png](https://dev-media.amazoncloud.cn/2ccdc373e19a46dbb700aac35e75c12a_31.png "31.png")
提交并确认失效完成后,再次访问/index.html 页面,即可看到失效动作完成,再次访问缓存状态为 Miss。
![32.png](https://dev-media.amazoncloud.cn/4735650c2efb4c04815c235349071dc7_32.png "32.png")
#### **总结**
在此篇小指南中,我们了解到了如何进一步使用 CloudFront 实现更多灵活的设置,包括 定制缓存策略 / 设置源服务主备逻辑 / 针对回源请求进行制定 / 修改业务所需的响应头以及如果定制错误响应,根据本篇的指引,您可根据业务需求灵活构建 CloudFront 的行为以及如果响应客户请求。
#### 亚马逊云科技
##### **CloudFront 部署小指南系列文章**
[Amazon CloudFront](https://aws.amazon.com/cn/cloudfront/?trk=cndc-detail) 部署小指南 (二)- 进阶部署:
https\://aws.amazon.com/cn/blogs/china/amazon-cloudfront-deployment-handbook-part-two/?trk=cndc-detail
[Amazon CloudFront](https://aws.amazon.com/cn/cloudfront/?trk=cndc-detail) 部署小指南 (三)- 持续部署:
https\://aws.amazon.com/cn/blogs/china/amazon-cloudfront-deployment-handbook-part-three/?trk=cndc-detail
[Amazon CloudFront](https://aws.amazon.com/cn/cloudfront/?trk=cndc-detail) 部署小指南(四)- CloudFront Function 基础与诊断:https\://aws.amazon.com/cn/blogs/china/amazon-cloudfront-deployment-handbook-part-four/?trk=cndc-detail
[Amazon CloudFront](https://aws.amazon.com/cn/cloudfront/?trk=cndc-detail) 部署小指南(五)- 使用 Amazon 边缘技术优化游戏内资源更新发布:https\://aws.amazon.com/cn/blogs/china/amazon-cloudfront-deployment-handbook-part-five/?trk=cndc-detail
[Amazon CloudFront](https://aws.amazon.com/cn/cloudfront/?trk=cndc-detail) 部署小指南(六)- Lambda\@Edge 基础与诊断:https\://aws.amazon.com/cn/blogs/china/amazon-cloudfront-deployment-handbook-part-six/?trk=cndc-detail
#### **本篇作者**
![34.jpg](https://dev-media.amazoncloud.cn/b43cb85f7f5e474486dbf563feb799f8_34.jpg "34.jpg")
**王骏兴**
*亚马逊云科技边缘产品架构师,负责亚马逊云科技 Edge 服务领域在中国的技术推广。在 CDN 内容分发以及 WAF 领域拥有多年实战经验,专注于边缘服务设计以及体验优化。*
![35.jpg](https://dev-media.amazoncloud.cn/79fa9956c6fe4eed899a136c63abdcfe_35.jpg "35.jpg")
**\
崔俊杰**
*亚马逊云科技高级产品解决方案架构师,负责亚马逊云科技云边缘安全相关的服务产品。为亚马逊云用户提供 DDoS 防御/网站前端安全防御/域名安全相关的产品咨询。对 Cloudfront,Shield,WAF,Route53,Global Accelerator 等云边缘安全相关产品有深入了解。在计算机安全、数据中心和网络领域有多年的工作经验。*