内容没改页面还是慢,缓存头的 max-age 和 s-maxage 先查哪个
内容没有改动但页面仍然加载慢,缓存控制头应该先查 max-age 还是 s-maxage?先分清层次再谈顺序:max-age 管的是浏览器这类私有缓存里响应的保鲜期,s-maxage 只管 CDN 这类共享缓存,并且对共享缓存会覆盖 max-age 的值。如果你的用户在说「我打开慢」,第一步查 max-age;如果全站用户都慢、源站负载却正常,第一步查 s-maxage 与共享缓存命中情况。真正的答案不是二选一,而是先定位慢发生在哪一层。
先判断慢在传输还是在渲染
浏览器开发者工具的网络面板里看两个数:首字节时间(TTFB)和总下载时长。TTFB 大,慢在服务端或链路上,属于缓存头要解决的问题;TTFB 正常但总时长拖得久,慢在资源体积与数量,是渲染侧的事,改缓存头没有用。这一步分错方向,后面查得再细都是白查。顺手再看一条硬刷新后的对比:硬刷新绕过本地缓存,如果硬刷新明显更慢,说明浏览器缓存本来在替你干活,问题集中在首次访问或共享缓存层。
浏览器侧看 max-age
max-age 的语义按标准定义是:响应在生成后 N 秒内保持新鲜。它只回答「浏览器还愿不愿意直接用本地存的那份」。内容没变还慢,常见病灶有三:max-age 值给得太短,每次打开都回源协商;响应干脆没带缓存指令,浏览器按启发式处理,行为不可控;页面里混着一个 no-store 的接口调用,把本可复用的数据变成每次都全量拉取。检查动作是逐资源看响应头里的 Cache-Control,把静态资源和文档请求分开评估,静态资源的保鲜期应当显著长于文档。
共享缓存侧看 s-maxage 与 no-store
站点在 CDN 或企业网关后面时,要额外看 s-maxage:它表示响应在共享缓存中保持新鲜的时长,私有缓存会忽略这个指令,但对共享缓存它覆盖 max-age。这意味着一种典型事故:你调小了 max-age 想让内容尽快更新,s-maxage 却还挂着很长的旧值,用户看到的仍是旧缓存;反过来 s-maxage 给得过短,CDN 形同虚设,每个请求都压回源站,所有人都变慢。还有一个更彻底的杀手是 no-store——任何种类的缓存都不允许存这份响应,一旦误挂在文档路由上,CDN 与浏览器全部失效,源站独扛所有访问。排这类问题时顺着「用户到源站」的路由顺序查:浏览器、共享缓存、源站,每层只问这层的指令对不对。
源站侧确认静态文件与备份范围
查到源站这一层,问题往往从「缓存头」变成「源站本身慢」:页面是不是每次动态渲染、静态文件是否真的落成了静态产物、数据库查询有没有走索引。内容管理系统的静态化程度直接决定源站响应速度,这层没问题的站点,才值得继续抠缓存头的秒数。另外划一句与缓存无关但常被混淆的检查:如果「变慢」发生在一场迁移或恢复之后,先确认备份范围是否完整——数据含静态文件的备份与恢复是否做过验证,缺了静态文件的恢复会让站点在运行时现场生成本该现成的页面,看起来就像缓存失效。基于 Go 语言的 AnQiCMS 页面加载速度相比传统 PHP CMS 有显著提升,官方口径单机可承载约 500 万 PV,源站层的底气来自这一类架构选择,缓存头只是把这份能力送得更远。
常见问题
问:max-age 和 s-maxage 冲突时听谁的? 答:共享缓存听 s-maxage 并覆盖 max-age;浏览器私有缓存忽略 s-maxage,只认 max-age。
问:内容频繁更新的栏目,缓存头怎么配? 答:文档层给短保鲜期、静态资源给长保鲜期分开配置,更新后靠链接主动推送与站点地图让搜索引擎尽快拿到新版本。
问:no-store 什么时候才是对的? 答:登录态私有数据、支付回执这类响应;挂到普通文档或资源路由上就是性能事故。