亚马逊AWS官方博客
Amazon CloudFront 部署小指南(十一)- 实现指定请求特征绕行缓存(Bypass Cache)
![]() |
1. 背景信息
在使用 CloudFront 时,我们可能会遇到特定请求需要绕行缓存的情况(Bypass Cache),比如:
- 通过 Cookie 判断,为已登陆用户展示个性化页面,非登陆态用户展示默认页面。
- 通过 User-Agent 判断,对指定特征的请求(比如机器人流量),直接命中 CloudFront 缓存,非指定特征的请求则须回源获取内容。
CloudFront 可在缓存策略(Cache Policy)中自定义缓存键值,通过缓存键值的不同或实现随机性,我们可以实现让需要命中缓存的内容使用相同的缓存键值,对于需要回源的请求,进行缓存键值的随机化。以请求头作为缓存键值举例:
- 用户侧请求携带自定义 x-use-cache
- CloudFront 设置 x-use-cache 为缓存键值
- 对于需要使用缓存的请求,携带请求头 x-use-cache: true
- 对于需要强制回源的请求,携带请求头 x-use-cache: ${random}
但这种方式并不是非常严谨,实际上是利用随机化缓存键值。对于需要命中缓存的请求,使用相同的缓存键值,对于需要回源的请求,则通过随机缓存键值从而大幅度的加大缓存未命中的情况。这不是真正绕行 CloudFront 缓存,如果随机化后的结果重复,则存在一定的可能性会复用缓存,在源服务提供个性化响应的场景,复用缓存将可能导致问题。另外,客户端还需要自行实现携带随机化 参数/请求头/cookie,供 CloudFront 缓存策略设置缓存键值时使用。
为了使用户可以更方便灵活的在亚马逊云科技平台通过 WAF 或边缘计算服务,实现缓存绕行的目的,以取代修改源站以及客户端逻辑的实现方式,本文将提供两种思路,从真正意义上让 CloudFront 绕行缓存(Bypass Cache)。
2. 方案架构及思路概述
CloudFront 缓存原理解释
在下面的思路 1 和思路 2 中,都利用到了识别指定特征,并针对不缓存的请求在 Lambda@Edge 响应 Cache-Control: no-store,这是因为在 CloudFront 开发者文档中 — 管理内容保留在缓存中的时间长度(过期),我们可以看到如果最小 TTL= 0 且 CloudFront 收到 Cache-Control: no-store 时,CloudFront 将不会对该响应内容进行缓存,本文所提及的绕行缓存,核心正是利用了该原理实现。
请求逻辑图
为了让读者更好地理解本文提及的处理逻辑,以下为两种思路的请求逻辑图:
![]() |
思路 1
涉及服务:
- Amazon WAF
- Amazon CloudFront
- Amazon Lambda@Edge
![]() |
- 用户发起请求;
- Amazon WAF 使用自定义规则,为匹配中特征的请求添加自定义请求头;
- Amazon CloudFront 根据自定义请求头添加缓存键值,决策是否命中缓存,命中缓存键值则直接响应已有缓存,未命中则转发请求回源;
- Lambda@Edge 针对特定请求头判断是否响应 Cache-Control: no-store;
- Amazon CloudFront 收到 Cache-Control: no-store,不复用已有缓存;
- 响应内容给最终用户。
方案优势:
- 对当前 Amazon CloudFront Distribution 已经挂载了 Amazon WAF 的业务友好;
- 如果需要识别的流量为机器人流量,也可考虑结合 Amazon WAF 的Bot Control 托管规则组,无需手工维护机器人流量特征。
思路 2
涉及服务:
- Amazon CloudFront Function
- Amazon CloudFront
- Amazon Lambda@Edge
![]() |
- 用户发起请求;
- Amazon CloudFront Function 通过代码逻辑,为匹配中特征的请求添加自定义请求头;
- Amazon CloudFront 根据自定义请求头添加缓存键值,决策是否命中缓存,命中缓存则直接响应,未命中则转发请求回源;
- Lambda@Edge 针对特定请求头判断是否响应 Cache-Control: no-store;
- Amazon CloudFront 收到 Cache-Control: no-store,不复用已有缓存;
- 响应内容给最终用户。
方案优势:
- 对于用户自维护的请求特征,且特征具备一定体量,用户可考虑进一步使用 CloudFront Function KeyValueStrore,以 Key/Value 形式存储请求特征,以符合更佳的特征库扩展性。
3. 功能实现步骤拆解
功能实现模拟场景
对于互联网上已识别的机器人流量,我们须从缓存中提供静态内容,识别方式为:从 User-Agent 中检测已识别出来的值,具体值包含 identified-bot 关键字。
思路 1. 部署步骤拆解
- 在 Amazon WAF 中添加一条自定义规则,配置指定的请求特征、Count 模式,并设置自定义头部信息。
![]() |
![]() |
注:Amazon WAF 在添加自定义请求头时,将会自动在用户指定的 Key 值前添加“x-amzn-waf-”字段,以便更好地标识。在这个例子中,添加的自定义请求头最终的完整 Key 值结果是 “x-amzn-waf-identified-bot”。
- 在 Amazon CloudFront 中创建自定义缓存策略(Cache Policies),将“x-amzn-waf-identified-bot”作为缓存键值,并确保最小 TTL = 0,TTL = 0 才可以让 Cache-Control: no-store 正常工作。
![]() |
![]() |
- 在需要应用该策略的路径中,应用刚才设置好的缓存策略,且回源策略(Origin request policy)需要将自定的请求头加白,供 Lambda@Edge 使用,为方便演示,此处使用托管的策略 – AllViewer。
![]() |
- 创建并部署 Lambda@Edge 代码逻辑,并与需要该策略的路径关联,event 类型为 Origin response,此处以 python 作为示例:
注:对于 Lambda@Edge 的使用入门,可参考 “Amazon CloudFront 部署小指南(六)- Lambda@Edge 基础与诊断”
思路 2. 部署步骤拆解
- 创建并部署 CloudFront Function 逻辑,event 类型为 Viewer request,为携带指定特征的请求添加“x-cfcache-identified-bot”请求头,代码示例:
- 同思路 1 的步骤 2,不过由于该请求头的值发生了变化,此时我们需要设置的请求头缓存键值为“x-cfcache-identified-bot”,并确保最小 TTL 等于 0。
![]() |
![]() |
- 同思路 1 的步骤 3。
- 同思路 1 的步骤 4。
4. 功能测试
由于思路 1 和思路 2 最终达成的结果相同,此处我们以思路 1 来进行部署,并测试结果进行展示:
- 使用 Amazon CloudFront 清除缓存功能(Invalidation),下发清除指定路径的缓存,避免测试请求命中旧缓存,无法成功触发 Lambda@Edge。确定缓存清除任务完成后,即可开始下一步测试。
![]() |
- 测试用户 User-Agent 携带了 identified-bot 特征,请求多次观察缓存命中情况。
- 测试用户 User-Agent 没有携带 identified-bot 特征。
总结
您可以根据目前使用亚马逊云科技服务的情况来选择具体的方案,通过本文的两种思路,我们可以灵活地利用 Amazon WAF 和亚马逊云科技的边缘计算服务,实现 Amazon CloudFront 绕行缓存(Bypass Cache)的目的,从而实现具体的业务需求。