缓存与重新验证
缓存是一种存储数据获取和其他计算结果的技术,以便将来对相同数据的请求能够更快地得到响应,而无需重复执行这些工作。而重新验证则允许您更新缓存条目,而无需重新构建整个应用程序。
Next.js 提供了几个 API 来处理缓存和重新验证。本指南将引导您了解何时以及如何使用它们。
fetch
默认情况下,fetch
请求不被缓存。您可以通过将 cache
选项设置为 'force-cache'
来缓存单个请求。
export default async function Page() {
const data = await fetch('https://...', { cache: 'force-cache' })
}
须知:尽管
fetch
请求默认不被缓存,Next.js 会预渲染包含fetch
请求的路由并缓存 HTML。如果您想确保某个路由是动态的,请使用connection
API。
要重新验证 fetch
请求返回的数据,您可以使用 next.revalidate
选项。
export default async function Page() {
const data = await fetch('https://...', { next: { revalidate: 3600 } })
}
这将在指定秒数后重新验证数据。
请参阅 fetch
API 参考以了解更多信息。
unstable_cache
unstable_cache
允许您缓存数据库查询和其他异步函数的结果。要使用它,请将 unstable_cache
包装在函数周围。例如:
import { db } from '@/lib/db'
export async function getUserById(id: string) {
return db
.select()
.from(users)
.where(eq(users.id, id))
.then((res) => res[0])
}
import { unstable_cache } from 'next/cache'
import { getUserById } from '@/app/lib/data'
export default async function Page({
params,
}: {
params: Promise<{ userId: string }>
}) {
const { userId } = await params
const getCachedUser = unstable_cache(
async () => {
return getUserById(userId)
},
[userId] // add the user ID to the cache key
)
}
该函数接受一个可选的第三个对象来定义缓存应如何重新验证。它接受:
tags
:Next.js 用于重新验证缓存的标签数组。revalidate
:缓存应重新验证的秒数。
const getCachedUser = unstable_cache(
async () => {
return getUserById(userId)
},
[userId],
{
tags: ['user'],
revalidate: 3600,
}
)
请参阅 unstable_cache
API 参考以了解更多信息。
revalidateTag
revalidateTag
用于根据标签和事件重新验证缓存条目。该函数现在支持两种行为:
- 使用
profile="max"
:采用陈旧时重新验证的语义,在后台获取新内容时提供陈旧内容。 - 不带第二个参数:立即使缓存失效的旧行为(已弃用)。
要在 fetch
中使用它,请首先使用 next.tags
选项标记该函数。
export async function getUserById(id: string) {
const data = await fetch(`https://...`, {
next: {
tags: ['user'],
},
})
}
或者,您可以使用 tags
选项标记 unstable_cache
函数。
export const getUserById = unstable_cache(
async (id: string) => {
return db.query.users.findFirst({ where: eq(users.id, id) })
},
['user'], // Needed if variables are not passed as parameters
{
tags: ['user'],
}
)
然后,在 路由处理程序 或 服务器动作中调用 revalidateTag
。
import { revalidateTag } from 'next/cache'
export async function updateUser(id: string) {
// Mutate data
revalidateTag('user', 'max') // Recommended: Uses stale-while-revalidate
}
您可以在多个函数中重用相同的标签,以一次性重新验证所有这些函数。
请参阅 revalidateTag
API 参考以了解更多信息。
revalidatePath
revalidatePath
用于在事件发生后重新验证路由。要使用它,请在 路由处理程序 或 服务器动作中调用它。
import { revalidatePath } from 'next/cache'
export async function updateUser(id: string) {
// Mutate data
revalidatePath('/profile')
请参阅 revalidatePath
API 参考以了解更多信息。
updateTag
updateTag
专门设计用于服务器动作,以便在“读写一致性”(read-your-own-writes)场景中立即使缓存数据失效。与 revalidateTag
不同,它只能在服务器动作中使用,并立即使缓存条目失效。
import { updateTag } from 'next/cache'
import { redirect } from 'next/navigation'
export async function createPost(formData: FormData) {
// Create post in database
const post = await db.post.create({
data: {
title: formData.get('title'),
content: formData.get('content'),
},
})
// Immediately expire cache so the new post is visible
updateTag('posts')
updateTag(`post-${post.id}`)
redirect(`/posts/${post.id}`)
}
revalidateTag
和 updateTag
之间的主要区别:
updateTag
:仅在服务器动作中使用,立即使缓存失效,适用于“读写一致性”场景。revalidateTag
:可在服务器动作和路由处理程序中使用,支持带有profile="max"
的陈旧时重新验证。
请参阅 updateTag
API 参考以了解更多信息。
这有帮助吗?