← 返回题目列表

SSR 页面缓存失效如何设计?如何避免用户看到旧内容?

中等 第 19 / 25 题 更新于 2026/07/29
SSR缓存失效CDN一致性

简化版

SSR 缓存失效要先明确缓存层级:浏览器、CDN、SSR 进程、本地内存、后端缓存都可能缓存页面或数据。常见策略有 TTL 自然过期、主动 purge、按 tag 失效、版本号、stale-while-revalidate 和后台刷新。设计时要在性能和新鲜度之间取舍,关键页面可以短 TTL 或主动失效,内容页可以接受短时间 stale。

详细版

SSR 页面缓存能显著降低 TTFB 和服务端压力,但缓存失效设计不好,会出现商品价格旧、库存旧、登录态串、活动配置不生效等问题。

页面缓存不能只看 URL,还要看语言、地区、设备、登录态、A/B 实验等维度。个性化内容如果混进公共缓存,会产生严重事故。

面试里要把缓存失效讲成“层级 + key + TTL + 主动失效 + 降级兜底”,而不是只说清缓存。

完整版教学

一、先识别缓存层级

浏览器可能缓存 HTML 或静态资源。

CDN 可能缓存 SSR 输出。

SSR 服务内部可能缓存渲染结果或接口数据。

后端服务和数据库前面也可能有缓存。

同一个页面旧内容可能来自任意一层。

二、缓存 key 设计

维度是否常见示例
URL必须/product/1
语言多语言站必须zh-CNen-US
地区有地域内容时需要华东、华北
登录态个性化页面需要anonymous、member
设备差异 HTML 时需要mobile、desktop
实验分组A/B 时需要groupA、groupB

缓存 key 少了会串内容,太多会降低命中率。

三、TTL 和主动失效

TTL 简单可靠,但内容会在过期前保持旧版本。

主动 purge 更新更及时,但依赖发布系统、CMS 或后端事件通知。

按 tag 失效适合内容关联复杂的页面,例如一个作者更新影响多个列表页。

stale-while-revalidate 允许先返回旧内容,再后台刷新缓存。

缓存失效不是越实时越好,实时性、成本和稳定性要一起平衡。

四、代码示例

export async function renderArticlePage(id: string) {
  const cacheKey = `article:${id}:zh-CN`;
  const cached = await pageCache.get(cacheKey);
  if (cached) return cached;

  const article = await getArticle(id);
  const html = await renderHtml(article);
  await pageCache.set(cacheKey, html, { ttl: 60, tags: [`article:${id}`] });
  return html;
}

真实项目还要处理并发回源,避免缓存刚失效时大量请求同时打到 SSR 服务。

五、防止缓存击穿

热点页面失效时要加锁或请求合并。

可以让一个请求负责回源,其他请求等待或返回 stale 内容。

对后端接口也要设置超时和降级。

缓存系统异常时,SSR 服务不能无限等待。

六、个性化内容要谨慎

用户昵称、购物车数量、会员价格不适合进入公共 HTML 缓存。

可以把公共内容 SSR 缓存,个性化区域客户端再请求。

也可以按登录态拆缓存,但要确保 Cookie 和缓存策略正确。

敏感页面通常不缓存 HTML,只缓存底层公共数据。

七、误区和追问

  • 误区:SSR 缓存只要设置 TTL 就够。 TTL 只能自然过期,无法解决强实时更新。
  • 误区:页面 URL 相同就能共用缓存。 语言、地区、登录态、实验分组都可能改变 HTML。
  • 误区:缓存失效就是删除 CDN。 SSR 进程、接口层和后端也可能有缓存。
  • 追问:如何避免缓存刚失效时流量打爆服务? 用请求合并、互斥锁、预热、stale-while-revalidate。
  • 追问:价格页能不能缓存? 可以缓存公共结构,但价格和库存要看实时性要求,常需短 TTL 或接口实时获取。
  • 追问:如何排查旧内容来自哪里? 在响应头或日志里标记缓存层级、命中状态、版本和生成时间。

八、面试收束

SSR 缓存失效的好答案要能体现系统观。

你需要说明缓存层级、key 维度、失效方式、击穿保护和个性化隔离。