创作说明:本文由 AI 辅助整理,协议说明参考 MDN。文中的路径和版本号均为假设示例,不代表某个生产站点的配置或测试结果。
假设一个站点始终使用 /download/current.exe,发布时直接替换这个路径对应的文件。服务器目录里已经是新版,并不能证明用户收到的也是新版。中间的 CDN 或浏览器,可能仍在复用以前的响应。
排查时先列出这条链路:下载按钮 → 跳转地址 → 实际文件地址 → 缓存层 → 源站。任意一层保留旧内容,都可能让用户继续拿到旧版。
一、先分清两个缓存指令
Cache-Control: no-cache 允许存储响应,但再次使用前需要验证;no-store 则要求不要存储本次响应。把源站改成 no-store,也不会自动删除此前已存在的缓存。[1]
因此,“配置已经改了”与“旧缓存已经失效”需要分别验证。仅修改源站响应头,不能当作所有缓存节点都已更新的证据。
二、给不同路径不同的职责
一种便于维护的设计是把“当前下载入口”和“具体版本文件”分开:
| 路径示例 | 职责 | 发布约定 |
|---|---|---|
| /download/current | 指向当前版本 | 发布时可以更新目标;检查该响应本身的缓存策略 |
| /releases/app-1.2.0-a1b2c3.exe | 保存某个确定版本 | 同一路径不覆盖为另一份内容 |
| /releases/app-1.3.0-d4e5f6.exe | 保存下一版本 | 新版本使用新地址 |
版本号后的短字符串仅是路径示意,不是完整校验值。文件完整性仍应使用可信发布清单中的完整摘要核对。
固定版本文件若确实不会改变,可以考虑较长缓存时间。固定下载入口则要按业务的新鲜度要求设置缓存,避免长期记住旧的跳转目标。若使用 immutable,它表达的是响应在新鲜期内不会变化的约定,前提是发布流程真的遵守这个约定。[1]
三、必须覆盖原地址时,怎样检查
有些业务必须保留 current.exe。此时建议按下面的顺序检查:
- 在源站确认新文件已完整就位,并记录版本、大小和摘要。
- 记录最终下载响应的 Cache-Control、ETag、Last-Modified、Age 等可用字段。
- 检查 CDN 的缓存规则是否覆盖了源站策略,以及旧对象是否需要按服务商提供的方式刷新。
- 用同一个下载入口重新下载到新的本地文件,核对实际内容。不要拿此前下载的旧文件作为本轮结果。
ETag 是用于验证资源版本的标识,不应直接当成通用文件哈希。仅比较文件名或大小,也不能证明内容相同。
四、怎么判断修复完成
给这个假设站点设计验收时,可以分别记录:源站文件摘要、公开入口最终地址、完整下载文件摘要。三者关联起来,才能说明“当前入口交付了预期版本”。
一次成功下载只能证明这次请求的结果。多个缓存区域或不同访问路径仍需按业务范围验证。如果有一次结果不一致,先保留它的时间、路径及响应头,再追查命中的缓存或发布节点。
对需要经常换包的站点,把版本文件保留为不可变对象,通常比频繁覆盖同一地址更容易追踪和回退。是否采用这种设计,还要结合存储成本、链接兼容性和实际发布流程决定。
参考资料:
[1] MDN:Cache-Control
[2] MDN:ETag