Menu

缓存和重新验证

缓存

缓存是存储数据以减少对服务器请求次数的过程。Next.js 为单个数据请求提供了内置的 数据缓存,让你能够精细控制缓存行为。

fetch 请求

默认情况下,fetch 请求会在运行时获取新鲜数据。

要缓存单个 fetch 请求,你可以使用 cache: 'force-cache' 选项:

// 'force-cache' 是默认值,可以省略
fetch("https://...", { cache: "force-cache" });

要选择不缓存单个 fetch 请求,你可以使用 cache: 'no-store' 选项:

layout.js
fetch("https://...", { cache: "no-store" });

进阶:如果在布局或页面段中有多个 fetch 请求,你可以使用 const dynamic = 'force-dynamic'const fetchCache = 'force-no-store' 段配置选项 来配置该段中所有数据请求的缓存行为。

数据获取库和 ORM

数据请求是否被缓存将取决于你的数据获取库、数据库客户端或 ORM 的默认语义。

要缓存特定请求,你可以使用 unstable_cache API:

@/app/lib/data.ts
import { unstable_cache as cache } from "next/cache";
 
export async function getPosts() {
  cache();
 
  try {
    // 获取数据
  } catch (error) {}
}
@/app/lib/data.js
import { unstable_cache as cache } from "next/cache";
 
export async function getPosts() {
  cache();
  try {
    // 获取数据
  } catch (error) {}
}

要选择不缓存特定请求,你可以使用 unstable_noStore API:

@/app/lib/data.ts
import { unstable_noStore as noStore } from "next/cache";
 
export async function getTransactions() {
  // 防止响应被缓存。
  // 这等同于 fetch(..., {cache: 'no-store'})。
  noStore();
 
  try {
    // 获取数据
  } catch (error) {}
}
@/app/lib/data.js
import { unstable_noStore as noStore } from "next/cache";
 
export async function getTransactions() {
  // 防止响应被缓存。
  // 这等同于 fetch(..., {cache: 'no-store'})。
  noStore();
 
  try {
    // 获取数据
  } catch (error) {}
}

重新验证数据

重新验证是清除数据缓存并重新获取最新数据的过程。当你的数据发生变化,你想确保显示最新信息的同时仍然享受静态渲染的速度时,这很有用。

缓存的数据可以通过两种方式重新验证:

  • 基于时间的重新验证:在一定时间过后自动重新验证数据。这适用于不经常变化且新鲜度不那么重要的数据。
  • 按需重新验证:基于事件 (例如表单提交) 手动重新验证数据。按需重新验证可以使用基于标签或基于路径的方法一次性重新验证一组数据。当你想确保尽快显示最新数据时 (例如当你的无头 CMS 中的内容更新时),这很有用。

基于时间的重新验证

要按时间间隔重新验证数据,你可以使用 fetchnext.revalidate 选项来设置资源的缓存生命周期 (以秒为单位)。

fetch("https://...", { next: { revalidate: 3600 } }); // 最多每小时重新验证一次

或者,要重新验证路由段中的所有请求,你可以使用 段配置选项

layout.js
export const revalidate = 3600; // 最多每小时重新验证一次

了解 基于时间的重新验证如何工作

值得注意的是

  • 如果在静态渲染的路由中有多个 fetch 请求,每个请求的重新验证频率不同,将使用所有请求中最短的时间。
  • 对于动态渲染的路由,每个 fetch 请求将独立重新验证。
  • 为了节省服务器资源,我们建议尽可能设置较长的重新验证时间。例如,1 小时而不是 1 秒。如果你需要实时数据,考虑切换到 动态渲染 或客户端数据获取。

按需重新验证

可以使用 revalidatePathrevalidateTag API 按需重新验证数据。

服务器操作路由处理程序 中使用 revalidatePath 重新验证特定路由的数据:

@/app/actions.tsx
import { revalidatePath } from 'next/cache'
 
export default async createPost() {
  try {
    // 修改数据
    revalidatePath('/posts')
  } catch(error) {}
 
}
@/app/actions.js
import { revalidatePath } from 'next/cache'
 
export default async createPost() {
  try {
    // 修改数据
    revalidatePath('/posts')
  } catch(error) {}
 
}

使用 revalidateTag 重新验证跨路由的 fetch 请求。

  1. 使用 fetch 时,你可以选择用一个或多个标签标记缓存条目。
  2. 然后,你可以调用 revalidateTag 重新验证与该标签相关的所有条目。

例如,以下 fetch 请求添加了缓存标签 collection

app/page.tsx
export default async function Page() {
  const res = await fetch("https://...", { next: { tags: ["collection"] } });
  const data = await res.json();
  // ...
}
app/page.js
export default async function Page() {
  const res = await fetch("https://...", { next: { tags: ["collection"] } });
  const data = await res.json();
  // ...
}

然后你可以通过调用 revalidateTag 来重新验证这个标记为 collectionfetch 调用:

@/app/actions.ts
"use server";
 
import { revalidateTag } from "next/cache";
 
export default async function action() {
  revalidateTag("collection");
}
@/app/actions.js
"use server";
 
import { revalidateTag } from "next/cache";
 
export default async function action() {
  revalidateTag("collection");
}

了解 按需重新验证如何工作

错误处理和重新验证

如果在尝试重新验证数据时抛出错误,最后一次成功生成的数据将继续从缓存中提供服务。在下一次后续请求中,Next.js 将重试重新验证数据。