介绍
Next.js App Router 具有强大的缓存架构,旨在优化加载速度并减少后端 API 开销。
然而,由于 Next.js 集成了多个缓存层,开发人员经常遇到调试问题。常见问题包括页面显示陈旧数据或 API 触发过于频繁。
本文通过解释 Next.js 中的四种缓存机制以及配置、刷新和无效它们的技术来消除混乱。
1. Next.js App Router 的四个缓存层
Next.js App Router 使用四个独立的缓存层:
[Client Side]
1. Router Cache (Temporary in-browser navigation cache)
│
[Server Side]
2. Request Memoization (React component render-cycle memory)
│
3. Data Cache (Persistent API request data across users)
│
4. Full Route Cache (Static HTML and RSC payloads at build-time)
下面总结一下各层的特点:
| 缓存层 | 地点 | 缓存内容 | 寿命 | 无效/重新生效 |
|---|---|---|---|---|
| 1.路由器缓存 | 客户 | RSC有效载荷 | 基于会话(分钟) | router.refresh(),服务器操作 |
| 2.请求记忆 | 服务器 | fetch 回复 | 单一渲染周期 | 根据请求自动清除 |
| 3.数据缓存 | 服务器 | API响应数据 | 坚持不懈 | revalidatePath、revalidateTag |
| 4.完整路由缓存 | 服务器 | HTML 和 RSC 有效负载 | 坚持不懈 | 重建,与数据缓存相关 |
2. 每个缓存层如何工作
① 请求记忆
如果在单个渲染请求期间在同一 React 组件树中多次获取相同的 URL 和配置,则仅执行第一个请求。其余调用从记忆缓存中读取。
// Component A
async function UserProfile() {
const res = await fetch('https://api.example.com/user'); // Fires API call
return <div>...</div>;
}
// Component B (rendered during the same cycle)
async function UserSettings() {
const res = await fetch('https://api.example.com/user'); // Reads from memoization cache
return <div>...</div>;
}
- 好处: 无需通过 props 向下传递数据。组件可以独立获取自己的数据需求。
② 数据缓存
数据缓存在传入请求和多个用户之间保留 API 响应数据。
默认情况下,Next.js 14 中的标准 fetch 请求缓存在此处(注意:Next.js 15 默认为未缓存的获取请求,尽管可以显式启用缓存)。
- 重新验证:
您可以设置基于时间的 TTL 或触发按需重新验证:
// Revalidate cache after one hour (3600 seconds) fetch('https://api.example.com/products', { next: { revalidate: 3600 } });
③ 全路由缓存
在构建时,Next.js 编译页面结构,呈现静态 HTML 和 RSC 有效负载。这对应于静态站点生成 (SSG)。
- 动态中断:
如果 Next.js 检测到动态函数(例如
cookies()、headers()或读取动态searchParams),它会绕过完整路由缓存。然后,该页面会根据每个请求动态呈现。
④ 路由器缓存
客户端浏览器缓存。当用户在路线之间导航时,Next.js 会在内存中缓存预取和访问过的页面。这使得即时来回导航成为可能。
- 无效:
在服务器操作内触发
revalidatePath会自动使路由器缓存失效,确保用户在下次导航时获得更新的布局。
3. 实用的缓存配置秘诀
场景 A:实时数据(绕过服务器缓存)
对于显示实时更新的页面(例如财务图表或实时状态板),请禁用 fetch 请求的缓存:
const res = await fetch('https://api.example.com/live-ticks', {
cache: 'no-store'
});
或者,强制整个路线保持动态:
export const dynamic = 'force-dynamic';
场景 B:按需重新验证 (revalidateTag)
对于在数据库记录更改(例如发布博客文章)时立即更新缓存内容非常有用。
// Append a tag to the fetch cache
const res = await fetch('https://api.example.com/posts', {
next: { tags: ['blog-posts'] }
});
// Trigger cache invalidation in a Server Action
import { revalidateTag } from 'next/cache';
async function updatePost() {
'use server';
await saveToDatabase();
// Clear all caches tagged with 'blog-posts'
revalidateTag('blog-posts');
}
结论
了解 Next.js 缓存依赖于区分 Request Memoization(一个渲染请求)和 Data Cache(跨请求持续存在)的生命周期。
要验证缓存设置,请在部署之前运行 next build 以检查哪些路由编译为静态 (○),哪些路由编译为动态 (λ)。

