CloudFront作为AWS的CDN服务,缓存键的构成直接影响对象是否命中边缘节点。在未规范化查询字符串时,GET /api/list?page=1&size=20和GET /api/list?size=20&page=1会被当作两个完全不同的缓存键,即使业务层认为两者等价。这种因参数顺序造成的缓存碎片,会降低命中率并增加源站压力。通过开启缓存策略中的Normalize Query Strings,可以让CloudFront在计算缓存键之前对查询参数按键名排序,进而把上述两个请求归并到同一个缓存条目。接下来从缓存键设计、工作原理和实际配置几个层面展开说明。

一、缓存键与查询字符串:参数顺序为什么会破坏缓存
CloudFront的缓存键由多个因素共同决定,包括分发域名、请求路径、查询字符串、请求头和Cookie等。如果缓存策略把查询字符串纳入缓存键,那么查询字符串会以原始顺序原样参与匹配。CDN节点在比较缓存键时按字节逐一比对,只要字符顺序不同,就会被视为不同的缓存对象。因此,两个业务上完全等价的请求,只是因为参数书写顺序不同,就无法复用同一份缓存。
以一个商品列表接口为例,假设它支持page、size、sort三个参数。前端可能因为不同页面生成顺序或用户点击路径不同,产生?page=2&sort=price&size=20、?sort=price&page=2&size=20、?size=20&page=2&sort=price等排列组合。这些请求在CloudFront上会各自回源一次,并分别缓存。虽然每个请求的结果可能一致,但缓存空间被浪费,源站QPS升高。查询参数越多,排列组合数量越大,缓存碎片问题越严重,极端情况下同一个资源可能产生数十份内容相同但键不同的副本。
要解决这个问题,不能只靠业务层强制统一参数顺序,因为客户端来源多样,难以完全控制。CloudFront提供的Normalize Query Strings选项可以从CDN侧统一处理:在计算缓存键前,将查询字符串按参数名排序,再拼接成规范化字符串。这样所有顺序不同但参数集合相同的请求都会命中同一个缓存对象,从根源上消除顺序敏感的缓存裂片。
二、Normalize Query Strings 的工作原理与配置方法
Normalize Query Strings开启后,CloudFront会解析URL中的查询字符串部分,按参数名进行字典序排序,然后重新组合。例如?b=2&a=1&c=3经过规范化后变成?a=1&b=2&c=3。该规范化只用于缓存键计算和匹配,回源请求仍然保持客户端原始查询字符串顺序,不会影响源站解析参数。如果参数名重复,CloudFront会保留多个同名参数并参与排序,但实际匹配行为可能因缓存策略配置而略有差异。
要在CloudFront控制台的缓存策略中开启该选项,必须先将QueryStringsConfig中的QueryStringBehavior设置为whitelist或all。如果查询字符串不包含在缓存键中,则规范化选项不会生效。配置时还需要决定是否将查询字符串转发给源站。对于大多数读接口,建议使用白名单方式只纳入影响响应内容的参数,例如分页、筛选、排序字段,避免无关参数导致缓存键膨胀。
下面通过AWS CLI创建一个开启规范化功能的缓存策略:
aws cloudfront create-cache-policy \
--cache-policy-config '{
"Name": "NormalizeQueryStringPolicy",
"MinTTL": 0,
"MaxTTL": 31536000,
"DefaultTTL": 86400,
"ParametersInCacheKeyAndForwardedToOrigin": {
"EnableAcceptEncodingGzip": true,
"HeadersConfig": {"HeaderBehavior": "none"},
"CookiesConfig": {"CookieBehavior": "none"},
"QueryStringsConfig": {
"QueryStringBehavior": "whitelist",
"QueryStrings": ["page", "size", "sort"],
"NormalizeQueryStrings": true
}
}
}'
上述配置将page、size、sort加入白名单作为缓存键组成部分,并开启NormalizeQueryStrings。这样客户端请求?page=2&sort=price&size=20与?sort=price&size=20&page=2在边缘节点会共享同一份缓存。创建策略后,需要将其关联到CloudFront分发的缓存行为。关联后等待一段时间让配置生效。注意:如果开启了NormalizeQueryStrings,但查询字符串行为是none,则CloudFront不会把查询字符串纳入缓存键,该选项自然没有效果。
三、缓存命中率提升的实际效果与边界注意事项
开启规范化后,缓存键由原本的顺序敏感变为顺序无关,相同参数集合的请求会收敛到一个缓存对象。以包含三个可选参数的接口为例,原本最多可能产生6种顺序组合,开启后只剩下1个缓存键。配合合理的TTL,命中率可从70%提高到90%以上。尤其是搜索、列表、报表类接口,参数组合固定但顺序多变的场景,收益非常明显。这样不仅减少源站负载,也降低终端用户延迟,因为更多请求直接在边缘返回。
Normalize Query Strings按参数名排序时,参数值的大小写不会被归一化。例如?Name=John和?name=John排序后键名可能相同,但值的大小写不同仍会导致缓存未命中。参数值中的空格和URL编码也可能影响一致性,%20与+在不同客户端编码下可能出现差异。CloudFront的规范化主要解决键顺序问题,不负责值级别的语义归一化。因此如果业务要求对参数值做大小写不敏感处理,还需要在源站或边缘函数中做额外处理。
规范化过程发生在每个请求的边缘节点上,虽然增加了微小的计算开销,但与回源成本相比可以忽略不计。该功能目前适用于HTTP和HTTPS请求,对POST等带请求体的方法并不适用,因为查询字符串通常只出现在GET请求中。开启后如果需要调试缓存键,可以通过CloudFront的日志或CloudFront Functions查看实际缓存的URL,但要注意日志中记录的是客户端原始请求还是规范化后的键,避免误判。
上线前,建议先在测试分发中开启该选项,观察缓存命中率指标变化。如果业务接口的结果确实不受参数顺序影响,再推广到生产环境。同时可以结合缓存TTL和查询字符串白名单,进一步减少无效参数对缓存键的影响。需要注意的是,一旦规范化后,之前已缓存的旧键对象不会自动合并或失效,可能需要手动失效或等待TTL过期才能完全体现效果。综合来看,Normalize Query Strings是一个低成本、高收益的缓存优化手段,适合大多数读多写少的CloudFront分发。
CloudFront Normalize Query Strings查询字符串排序缓存命中率修改时间:2026-09-26 19:49:36