HTTP 缓存、协商与发布失效
验证:未记录
- 适用版本
- 未记录
- 验证范围
- 尚未登记验证记录。
HTTP(Hypertext Transfer Protocol,超文本传输协议)缓存有浏览器私有缓存和代理/CDN(Content Delivery Network,内容分发网络)共享缓存。是否存、存多久、如何区分内容、更新后怎样失效是四个独立问题。
1. 一次读取的决策#
查缓存键 → 没有副本 → 请求源站 → 按策略保存
→ 有副本且新鲜 → 直接复用
→ 过期/要求验证 → If-None-Match → 304:复用正文
→ 200:替换正文ETag 是表示版本的校验标识,不保证一定是文件哈希。no-cache 允许存但复用前需验证;no-store 不允许存本次内容;private 禁止共享缓存存储。s-maxage 面向共享缓存,max-age 控制一般新鲜期。HTTP 缓存标准。
2. Hands-on:实测 200 → 304 → 更新后 200#
先启动 隔离实验环境,同一 Bash 会话保留 $HTTP_LAB_DIR:
curl -sS -D "$HTTP_LAB_DIR/first.headers" -o "$HTTP_LAB_DIR/first.body" http://127.0.0.1:18080/asset.txt
ETAG=$(awk 'tolower($1)=="etag:" {sub(/^[^:]*:[ \t]*/, ""); sub(/\r$/, ""); print; exit}' "$HTTP_LAB_DIR/first.headers")
test -n "$ETAG"
curl -sS -D - -o /dev/null -H "If-None-Match: $ETAG" http://127.0.0.1:18080/asset.txt
printf 'release-two-with-different-size\n' > "$HTTP_LAB_DIR/www/asset.txt"
sleep 1 # 给 Docker Desktop 绑定目录同步留出时间
curl -sS -D - -H "If-None-Match: $ETAG" http://127.0.0.1:18080/asset.txt预期依次 200、304、200,最后返回新内容与新 ETag。curl 不像浏览器一样自动维护内容缓存,这里显式发送条件头来观察协议。修改文件长度避免静态服务器依赖时间戳/长度生成的 ETag 在快速实验中不变。
3. 在真实 CDN 验收缓存键#
- 选择公开、可回收的测试对象,响应明确设置短 TTL(Time To Live,存活时间),记录发布版本。
- 对同一 URL 连续 GET,比较正文、Age、ETag 和供应商缓存命中头;没有 Age 不能单独证明未缓存。
- 若语言、国家、编码或 query 会改变内容,成对请求不同值,确认返回与缓存键一致。只转发请求头,不代表已纳入缓存键。
- 登录态/租户数据使用明确禁共享缓存策略;不能假定存在 Cookie 就自动绕过 CDN。
- 发布新版本后验证旧/新页面引用、304、压缩版本和错误响应缓存,最后执行受控失效或等待到期。
对应可部署案例见 CloudFront 缓存分区与验收。
4. 发布策略与回退#
| 对象 | 推荐策略 |
|---|---|
| 内容哈希命名的静态文件 | 长缓存 + immutable,更新时换 URL;保留旧文件覆盖回退窗口 |
| HTML/版本清单 | 短缓存或强制协商,避免指向已删除资源 |
| 敏感业务接口 | no-store,并核对 CDN 缓存规则,不能只改应用头 |
| 动态按 Origin 返回的跨域许可 | Vary: Origin,并核对实际边缘缓存键 |
回退同时考虑源站、CDN、浏览器和 Service Worker。删除源站对象不等于删除边缘副本;只把新响应改成 no-store 不会清空旧缓存。恢复实验文件用 printf 'release-one\n' > "$HTTP_LAB_DIR/www/asset.txt",再按首页清理。