上节我们了解了缓存机制,本节来深入学习缓存重新验证。重新验证是指在缓存过期后如何获取最新数据,这是保证数据新鲜度的关键机制。
重新验证概述
重新验证(Revalidation)是指清除缓存并获取最新数据的过程。Next.js 提供两种重新验证方式:
- 基于时间 - 设定时间间隔自动重新验证
- 按需 - 通过事件触发重新验证
理解这两种方式的区别和使用场景很重要。
基于时间的重新验证
设置重新验证间隔
最简单的方式是设置固定的重新验证时间:
// app/products/page.tsx
export const revalidate = 3600 // 每 1 小时重新验证
export default async function ProductsPage() {
const products = await getProducts()
return <ProductList products={products} />
}
使用 next.revalidate
更灵活的方式是在 fetch 请求中设置:
async function getProducts() {
const res = await fetch('https://api.example.com/products', {
next: { revalidate: 3600 },
})
return res.json()
}
export default async function ProductsPage() {
const products = await getProducts()
return <ProductList products={products} />
}
重新验证工作原理
基于时间的重新验证使用的是 Stale-While-Revalidate 策略:
T = 0 → 用户访问,数据被缓存
T = 1 → 用户访问,返回缓存数据(背景重新验证)
T = 2 → 用户访问,返回新数据
这意味着用户永远不会等待,总是能快速得到响应,同时数据也能保持相对新鲜。
按需重新验证
有时候我们希望在数据更新时立即重新验证,而不是等待缓存过期。这就是按需重新验证。
revalidatePath
根据特定路径重新验证缓存:
'use server'
import { revalidatePath } from 'next/cache'
export async function createPost(formData: FormData) {
const post = await db.post.create({
data: {
title: formData.get('title'),
content: formData.get('content'),
},
})
// 重新验证文章列表页面
revalidatePath('/posts')
// 重新验证首页(如果显示文章)
revalidatePath('/')
return post
}
revalidateTag
根据标签重新验证缓存,这种方式更加灵活:
'use server'
import { revalidateTag } from 'next/cache'
export async function updatePost(id: string, data: any) {
const post = await db.post.update({
where: { id },
data,
})
// 重新验证所有带 'posts' 标签的缓存
revalidateTag('posts')
return post
}
多个标签
一个数据更新可能影响多个缓存:
'use server'
import { revalidateTag } from 'next/cache'
export async function createComment() {
await db.comment.create(/* ... */)
// 重新验证多个缓存
revalidateTag('comments')
revalidateTag('posts') // 更新文章评论数
revalidateTag('user-activity')
}
后台重新验证
Next.js 支持后台重新验证,这意味着在重新验证时,用户仍然可以得到缓存的旧数据,而新数据在后台获取。
配置后台重新验证
export default async function Page() {
const res = await fetch('https://api.example.com/data', {
next: { revalidate: 3600 },
})
const data = await res.json()
return <div>{/* ... */}</div>
}
这样配置后,第一次访问会获取并缓存数据。后续访问会返回缓存数据,同时在后台重新验证。如果重新验证成功,下次访问就会返回新数据。
路由段配置
revalidate
设置页面的重新验证时间(秒):
// 每 1 小时重新验证
export const revalidate = 3600
dynamic
控制页面是静态还是动态渲染:
// 强制动态渲染(不缓存)
export const dynamic = 'force-dynamic'
// 强制静态渲染
export const dynamic = 'force-static'
// 自动选择(默认)
export const dynamic = 'auto'
重新验证策略
选择合适的重新验证策略很重要:
静态内容
适合不经常变化的内容:
// 博客文章、文档
export const revalidate = 86400 // 24 小时
动态内容
适合经常变化的内容:
// 用户数据、实时统计
export const dynamic = 'force-dynamic'
混合策略
同一个应用中不同部分使用不同策略:
// 文章列表 - 每 10 分钟更新
export const revalidate = 600
// 文章详情 - 每小时更新
export const revalidate = 3600
// 用户数据 - 实时
export const dynamic = 'force-dynamic'
实用建议
这里分享几个在缓存重新验证时特别实用的技巧。
根据数据更新频率选择策略
实际开发中,根据数据更新频率选择合适的策略特别重要:
// 不经常变化的数据可以长时间缓存
export const revalidate = 86400
// 经常变化的数据建议短时间缓存
export const revalidate = 60
// 实时数据最好不缓存
export const dynamic = 'force-dynamic'
使用标签进行精确控制
这个技巧特别有用——使用标签可以更精确地控制缓存重新验证:
// 获取数据时添加标签
const posts = await fetch('https://api.com/posts', {
next: { tags: ['posts', 'blog'] },
})
// 更新时按标签重新验证,更灵活
revalidateTag('posts')
避免过度重新验证
这里有个小建议:不要频繁重新验证不变的数据,这样会浪费资源:
// 避免这种情况 - 每秒重新验证太频繁
export const revalidate = 1
// 推荐这样做 - 选择合理的时间间隔
export const revalidate = 3600
总结
本节我们深入了解了缓存重新验证机制,包括基于时间和按需重新验证、后台重新验证、不同的重新验证策略等。合理使用重新验证能让你的应用既快速又能保持数据新鲜。
如果你对本节内容有任何疑问,欢迎在评论区提出来,我们一起学习讨论。