一个本应由边缘缓存直接返回的页面,有时会因为源站响应中的 Set-Cookie 或 Cache-Control 被重新送回源站。麻烦在于,这些响应头可能来自旧框架、共享中间件或无法立即修改的托管服务。Cache Response Rules 提供了一个更合适的控制点:在响应进入缓存决策流程时修正这些头部,而不必先改造源站。
问题不一定出在缓存键
排查缓存未命中时,开发者通常先检查 URL、查询参数和缓存键。但缓存系统除了判断“两个请求是否相同”,还必须判断“这个响应能不能存”。
下面两类响应头经常影响后一个判断:
Set-Cookie:表示响应希望在客户端写入 Cookie,往往暗示内容可能与会话有关。Cache-Control:private、no-store、no-cache等指令会限制共享缓存保存或复用响应。
例如,一个实际内容完全公开的静态页面,可能因为通用中间件附加了无关 Cookie:
HTTP/1.1 200 OK
Content-Type: text/html
Cache-Control: private, no-cache
Set-Cookie: tracking_id=abc123; Path=/
<html>...</html>
即使请求路径看起来适合缓存,响应头仍可能让边缘节点放弃缓存。结果是重复请求持续打到源站,增加延迟和源站负载。
Cache Response Rules 的关键意义不只是“能改响应头”,而是规则在缓存决策所需的时机生效。团队可以按主机名、路径或其他请求条件,定向移除意外的 Set-Cookie,或者把错误的缓存指令改成符合业务语义的值。
把规则限制在明确的公开内容上
响应头改写具有风险。Set-Cookie 和 private 有时确实在保护用户数据,不能因为命中率不理想就全站删除。
适合采用这类规则的对象通常具有几个特征:
- 响应内容对所有访问者一致。
- 页面不依赖登录状态、地区、权限或实验分组。
- 源站附加的 Cookie 与页面内容无关。
- 团队能够用清晰的路径表达式限定规则范围。
可以这样实践。假设 /assets/ 和 /public/ 下的内容已经确认是公开资源,可将规则表达为以下伪配置。字段名称需要按实际平台界面或 API 调整,这里只展示规则设计:
# 假设性示例:请映射到实际 Cache Response Rules 配置项
name: normalize-public-cache-headers
when:
hostname: www.example.com
path_prefix_any:
- /assets/
- /public/
actions:
remove_response_headers:
- Set-Cookie
set_response_headers:
Cache-Control: "public, max-age=300, s-maxage=3600"
这里刻意使用路径白名单,而不是对整个站点生效。max-age=300 控制浏览器缓存时间,s-maxage=3600 表达共享缓存可保存一小时;具体数值应依据内容更新频率确定。
不要把同样的规则套到 /account/、/checkout/ 或返回个性化信息的 API 上。否则共享缓存可能把一个用户的响应交给另一个用户。
用命令确认问题和改写结果
上线规则之前,先记录源站或边缘入口当前返回的关键头部。下面的脚本可以直接运行;将参数替换成要检查的 URL:
#!/usr/bin/env bash
set -euo pipefail
url="${1:-https://www.example.com/public/index.html}"
echo "Checking: $url"
curl --silent --show-error --output /dev/null --dump-header - "$url" \
| tr -d '\r' \
| awk 'BEGIN { IGNORECASE=1 }
/^HTTP\// ||
/^cache-control:/ ||
/^set-cookie:/ ||
/^age:/ ||
/^etag:/ ||
/^vary:/ ||
/^cf-cache-status:/ ||
/^x-cache:/ { print }'
保存为 check-cache.sh 后执行:
chmod +x check-cache.sh
./check-cache.sh https://www.example.com/public/index.html
应用规则后至少请求两次,因为第一次请求可能用于填充缓存:
for i in 1 2 3; do
echo "--- request $i ---"
./check-cache.sh https://www.example.com/public/index.html
sleep 2
done
验证时不要只寻找某个固定的命中标记。不同平台使用的诊断响应头不同,应重点确认:
- 不需要的
Set-Cookie是否只在目标路径上消失。 Cache-Control是否变成预期值。- 重复请求是否出现缓存命中或
Age增长迹象。 - 登录页、账户页和个性化 API 是否仍保持不可共享缓存的行为。
还可以分别带上两组测试 Cookie 请求同一资源,比较响应体哈希,确认内容确实不随会话变化:
url="https://www.example.com/public/index.html"
curl -fsS -H 'Cookie: session=test-user-a' "$url" | sha256sum
curl -fsS -H 'Cookie: session=test-user-b' "$url" | sha256sum
哈希一致不能独立证明内容永远安全,但它能帮助发现明显的个性化差异。更稳妥的做法是结合应用代码、模板逻辑和权限模型进行审查。
上线时把安全边界放在命中率之前
Cache Response Rules 适合解决“源站响应语义错误,但源站暂时难改”的问题,也可以作为迁移期间的控制层。不过,它不应永久掩盖应用对缓存语义的误解。有条件时,仍应让源站为公开内容返回正确的 Cache-Control,并避免无意义地设置 Cookie。
上线前可以使用这份检查表:
- 规则只匹配已经确认公开且非个性化的路径。
- 已检查
Vary、认证头、Cookie 和地区化逻辑。 - 缓存时间符合内容更新与回滚要求。
- 已验证命中、未命中和过期后的行为。
- 已准备快速禁用规则的操作路径。
- 已监控源站请求量、缓存命中率和错误率。
这项能力真正解决的是控制位置问题:当难以在源站清理意外响应头时,在缓存做出决定之前进行精确修正。规则越窄、验证越充分,它带来的收益就越可靠。