Next.js缓存策略 #
一、缓存概述 #
1.1 缓存类型 #
| 缓存类型 | 位置 | 说明 |
|---|---|---|
| 请求缓存 | 服务端 | fetch请求去重和缓存 |
| 全路由缓存 | 服务端 | 渲染结果缓存 |
| 路由缓存 | 客户端 | 路由段缓存 |
| 数据缓存 | 服务端 | fetch响应缓存 |
1.2 缓存流程 #
text
请求 → 路由缓存检查 → 全路由缓存检查 → 数据缓存检查 → 实际请求
↓ ↓ ↓
客户端缓存 服务端缓存 服务端缓存
二、请求缓存 #
2.1 自动去重 #
Next.js 自动对相同的 fetch 请求进行去重:
tsx
async function getUser() {
return fetch('https://api.example.com/user').then(res => res.json())
}
export default async function Page() {
const user1 = await getUser()
const user2 = await getUser()
return <div>{user1.name}</div>
}
只发送一次请求。
2.2 缓存键 #
缓存键由以下因素决定:
- URL
- 请求方法
- Headers
- 其他选项
tsx
fetch('https://api.example.com/data', {
headers: { 'Authorization': 'Bearer token' },
})
不同的 Headers 会产生不同的缓存。
2.3 禁用请求缓存 #
tsx
fetch('https://api.example.com/data', {
cache: 'no-store',
})
三、数据缓存 #
3.1 永久缓存 #
tsx
fetch('https://api.example.com/static-data', {
cache: 'force-cache',
})
3.2 不缓存 #
tsx
fetch('https://api.example.com/dynamic-data', {
cache: 'no-store',
})
3.3 定时重新验证 #
tsx
fetch('https://api.example.com/data', {
next: { revalidate: 60 },
})
3.4 基于标签的缓存 #
tsx
fetch('https://api.example.com/posts', {
next: { tags: ['posts'] },
})
触发重新验证:
tsx
import { revalidateTag } from 'next/cache'
revalidateTag('posts')
3.5 基于路径的缓存 #
tsx
import { revalidatePath } from 'next/cache'
revalidatePath('/blog')
revalidatePath('/blog/[slug]', 'page')
revalidatePath('/', 'layout')
四、全路由缓存 #
4.1 静态渲染 #
默认情况下,Next.js 会缓存静态渲染的路由:
tsx
export default async function Page() {
const data = await fetch('https://api.example.com/data')
return <div>{data}</div>
}
4.2 动态渲染 #
使用动态函数会禁用全路由缓存:
tsx
import { cookies } from 'next/headers'
export default async function Page() {
const cookieStore = await cookies()
const token = cookieStore.get('token')
return <div>{token}</div>
}
4.3 段配置 #
tsx
export const dynamic = 'force-dynamic'
export default async function Page() {
const data = await fetch('https://api.example.com/data')
return <div>{data}</div>
}
4.4 动态配置选项 #
| 配置 | 值 | 说明 |
|---|---|---|
| dynamic | ‘auto’ | 自动决定 |
| dynamic | ‘force-dynamic’ | 强制动态 |
| dynamic | ‘error’ | 静态时报错 |
| dynamic | ‘force-static’ | 强制静态 |
| dynamicParams | boolean | 允许动态参数 |
| revalidate | number | 重新验证时间 |
五、路由缓存 #
5.1 概念 #
路由缓存存储在客户端,用于快速导航:
tsx
<Link href="/about">关于</Link>
点击链接时,优先使用路由缓存。
5.2 缓存时间 #
| 路由类型 | 缓存时间 |
|---|---|
| 静态路由 | 5分钟 |
| 动态路由 | 不缓存 |
| 预加载路由 | 5分钟 |
5.3 刷新路由缓存 #
tsx
import { useRouter } from 'next/navigation'
export default function RefreshButton() {
const router = useRouter()
return (
<button onClick={() => router.refresh()}>
刷新
</button>
)
}
六、缓存失效 #
6.1 基于时间 #
tsx
export const revalidate = 3600
export default async function Page() {
const data = await fetch('https://api.example.com/data')
return <div>{data}</div>
}
6.2 按需重新验证 #
Server Action
tsx
'use server'
import { revalidatePath, revalidateTag } from 'next/cache'
export async function updatePost(slug: string) {
await updatePostInDatabase(slug)
revalidatePath(`/blog/${slug}`)
revalidateTag('posts')
}
API Route
tsx
import { revalidateTag } from 'next/cache'
import { NextResponse } from 'next/server'
export async function POST(request: Request) {
const body = await request.json()
revalidateTag(body.tag)
return NextResponse.json({ revalidated: true })
}
6.3 清除所有缓存 #
tsx
import { revalidatePath } from 'next/cache'
export async function clearAllCache() {
revalidatePath('/', 'layout')
}
七、缓存策略选择 #
7.1 静态内容 #
tsx
export const dynamic = 'force-static'
export default async function Page() {
const data = await fetch('https://api.example.com/static', {
cache: 'force-cache',
})
return <div>{data}</div>
}
7.2 动态内容 #
tsx
export const dynamic = 'force-dynamic'
export default async function Page() {
const data = await fetch('https://api.example.com/dynamic', {
cache: 'no-store',
})
return <div>{data}</div>
}
7.3 增量静态再生 #
tsx
export const revalidate = 60
export default async function Page() {
const data = await fetch('https://api.example.com/data', {
next: { revalidate: 60 },
})
return <div>{data}</div>
}
7.4 用户特定内容 #
tsx
import { cookies } from 'next/headers'
export default async function Page() {
const cookieStore = await cookies()
const userId = cookieStore.get('user_id')?.value
const data = await fetch(`https://api.example.com/user/${userId}`, {
cache: 'no-store',
})
return <div>{data}</div>
}
八、缓存调试 #
8.1 开发模式 #
开发模式下缓存默认禁用,可以通过以下方式启用:
tsx
fetch('https://api.example.com/data', {
cache: 'force-cache',
})
8.2 缓存头 #
查看响应头了解缓存状态:
text
x-nextjs-cache: HIT
x-nextjs-cache: MISS
x-nextjs-cache: STALE
8.3 日志 #
tsx
export default async function Page() {
console.log('Page rendered at:', new Date().toISOString())
const data = await fetch('https://api.example.com/data')
return <div>{data}</div>
}
九、最佳实践 #
9.1 分层缓存 #
tsx
export default async function Page() {
const staticData = await fetch('/api/static', {
cache: 'force-cache',
})
const semiStaticData = await fetch('/api/semi-static', {
next: { revalidate: 3600 },
})
const dynamicData = await fetch('/api/dynamic', {
cache: 'no-store',
})
return (
<div>
<StaticSection data={staticData} />
<SemiStaticSection data={semiStaticData} />
<DynamicSection data={dynamicData} />
</div>
)
}
9.2 缓存标签组织 #
tsx
const CACHE_TAGS = {
posts: 'posts',
users: 'users',
comments: 'comments',
} as const
fetch('/api/posts', {
next: { tags: [CACHE_TAGS.posts] },
})
9.3 条件缓存 #
tsx
export default async function Page() {
const isProduction = process.env.NODE_ENV === 'production'
const data = await fetch('https://api.example.com/data', {
cache: isProduction ? 'force-cache' : 'no-store',
})
return <div>{data}</div>
}
十、总结 #
缓存策略要点:
| 缓存类型 | 控制方式 | 适用场景 |
|---|---|---|
| 请求缓存 | fetch选项 | 请求去重 |
| 数据缓存 | cache/revalidate | API响应 |
| 全路由缓存 | dynamic配置 | 页面渲染 |
| 路由缓存 | 客户端自动 | 导航优化 |
下一步,让我们学习数据变更与重新验证!
最后更新:2026-03-28