Next.js App Router 缓存机制完全指南
梳理 App Router 中四层缓存的边界与失效策略,解决「改了数据页面却不更新」这一高频困惑。
Next.js App Router 的缓存机制是新手最容易困惑的部分。很多「数据没更新」「页面是旧的」问题,根源都在于没分清四层缓存各自的职责。
四层缓存
App Router 在请求链路上有四个缓存层:
- 请求记忆(Request Memoization):单次请求内,相同
fetch去重,避免重复请求; - 数据缓存(Data Cache):跨请求缓存
fetch结果,默认持久; - 全路由缓存(Full Route Cache):服务端把整页 HTML/RSC 缓存起来;
- 路由缓存(Router Cache):客户端把已访问页面的 RSC 载荷缓存在内存里。
数据缓存:最常被踩的坑
默认情况下,fetch 结果会被持久缓存。这意味着即使后端数据变了,页面也可能显示旧数据。控制手段:
// 完全禁用缓存
fetch(url, { cache: 'no-store' });
// 按时间重新验证(ISR)
fetch(url, { next: { revalidate: 60 } });
对于数据库直连(无 fetch),则用 unstable_noStore() 或 export const revalidate = 60 控制。
按需失效:revalidatePath
如果你希望「数据变了主动让缓存失效」,用 revalidatePath:
async function updatePost(id) {
await db.update(id);
revalidatePath(`/blog/${id}`);
}
这比盲目地禁用缓存更优雅,兼顾了新鲜度与性能。
路由缓存与客户端跳转
客户端路由跳转时,浏览器会优先复用 Router Cache 中的旧页面。这也是「服务端已更新、客户端仍显示旧内容」的原因。刷新页面或等待失效窗口即可看到新内容。
决策清单
- 数据实时性要求高 →
no-store; - 数据可容忍短延迟 →
revalidate; - 需要主动控制 →
revalidatePath; - 完全静态 → 默认缓存 + 构建时生成。
结语
缓存是性能与新鲜度的永恒博弈。Next.js 给了你充分的控制权,前提是你分得清每一层缓存各自管什么。这张地图,值得打印出来贴在工位。