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