HTML应设no-cache或max-age=0,must-revalidate以确保及时更新,避免CDN缓存旧版导致白屏;需禁用Set-Cookie、避免查询参数干扰、杜绝meta标签伪配置,核心是源站响应头精准控制与构建产物原子发布。

HTML静态内容不能依赖CDN边缘计算来“动态生成”或“执行逻辑”,它只能被字节级缓存和分发;所谓优化,本质是控制好Cache-Control、URL结构与回源行为——不是让CDN变聪明,而是让它少犯错。
为什么Cache-Control必须设为no-cache或max-age=0, must-revalidate
HTML是页面入口,哪怕内容看起来“静态”,也常隐含动态语义(如时间戳、AB测试开关、未登录态占位符)。如果设成public, max-age=3600,CDN会缓存一小时,用户看到的就是旧骨架,JS可能加载失败,CSS路径404,首屏白屏延长300ms以上。
-
no-cache:每次请求都向源站发带If-None-Match的验证请求,命中则返回304 Not Modified,复用本地缓存——平衡新鲜度与传输开销 -
max-age=0, must-revalidate:语义更明确,强制验证,避免某些CDN对no-cache实现不一致 - 绝对不要用
immutable或max-age=31536000——哪怕文件名带哈希(如index.a1b2c3.html),它仍是路由入口,不是纯静态资源
Set-Cookie头会让CDN跳过缓存,但你可能根本没意识到它存在
很多后端框架(如Express、Django)默认在响应中写Set-Cookie,哪怕只是csrftoken或sessionid。只要响应头里有这个字段,绝大多数CDN(Cloudflare、阿里云CDN、腾讯云CDN)会直接拒绝缓存该HTML响应,导致所有请求都回源。
- 检查
curl -I https://yoursite.com/输出,确认没有Set-Cookie出现在HTML响应头中 - 如果是SSR应用,确保渲染HTML时禁用会话中间件,或把cookie设置限定在API路径下(如只对
/api/设Set-Cookie) - 若必须保留cookie,可改用
Vary: Cookie,但会大幅降低CDN缓存命中率——一个用户一个缓存副本,基本失去CDN意义
查询参数(?v=1.2.3)不是缓存更新的可靠方式
把版本号塞进URL参数看似简单,但CDN默认把/index.html?v=1.2.3和/index.html?v=1.2.4当两个独立资源缓存。问题在于:你无法保证所有引用它的地方(比如PWA manifest、service worker precache列表、第三方埋点脚本)同步更新参数,容易出现HTML新、JS旧的错配。
立即学习“前端免费学习笔记(深入)”;
- 更稳妥的做法是用文件名哈希:
/index.a1b2c3.html,配合构建工具自动生成,URL变更即缓存失效 - 如果必须用参数,需在CDN后台显式配置“忽略特定查询参数”,例如忽略
v、utm_*等,否则每个分享链接都会打爆缓存空间 - 注意:
location.href或document.referrer里的参数不会影响CDN缓存键,只有实际HTTP请求的URL路径+参数才起作用
ESI(Edge Side Include)不是通用方案,别把它当模板引擎用
想在HTML里插入用户昵称或购物车数量?ESI(如<esi:include src="/api/user">)确实能在CDN边缘节点发起子请求并内联结果,但它不是标准能力,且调试极其困难。
- Akamai、Fastly原生支持ESI;Cloudflare需开启Workers + 自定义逻辑;国内主流CDN(如阿里云、腾讯云)默认关闭,需单独申请并审核
- ESI子请求走CDN内网链路,延迟低,但一旦
/api/user超时或返回非200,整个HTML响应可能失败或截断——错误不可见、不可监控 - 现代更推荐CSR(客户端渲染)+ 骨架HTML缓存:CDN只缓存不含用户数据的初始HTML,JS在浏览器里调用
fetch()拉取个性化内容,错误可捕获、可上报、可降级
真正卡住HTML缓存效果的,往往不是CDN配置多复杂,而是源站响应头里悄悄混进了Set-Cookie、构建产物漏掉了哈希、或者开发时顺手加了个meta http-equiv以为能生效——这些细节不查日志、不抓包,光看CDN后台规则永远发现不了。



















