数据获取、缓存与重新验证
数据获取是任何应用的核心部分。本文将介绍如何在 React 和 Next.js 中获取、缓存及重新验证数据。
数据获取有以下四种方式:
在服务端使用 fetch
获取数据
Next.js 扩展了原生的 fetch
Web API,允许您为服务端的每个 fetch 请求配置缓存和重新验证行为。React 则扩展了 fetch
功能,在渲染 React 组件树时自动记忆化 fetch 请求。
您可以在服务端组件中使用 async
/await
配合 fetch
,也可用于路由处理器和服务端动作。
例如:
须知:
数据缓存
缓存存储数据,避免每次请求都从数据源重新获取。
默认情况下,Next.js 会自动将 fetch
的返回值缓存在服务端的数据缓存中。这意味着数据可以在构建时或请求时获取、缓存,并在每次数据请求时重复使用。
使用 POST
方法的 fetch
请求也会被自动缓存。除非它位于使用 POST
方法的路由处理器中,此时不会被缓存。
什么是数据缓存?
数据缓存是一个持久的 HTTP 缓存。根据您的平台,缓存可以自动扩展并跨多个区域共享。
了解更多关于数据缓存的信息。
重新验证数据
重新验证是清除数据缓存并重新获取最新数据的过程。这在数据发生变化且您希望确保显示最新信息时非常有用。
缓存数据可以通过两种方式重新验证:
- 基于时间的重新验证:在一定时间间隔后自动重新验证数据。适用于变化不频繁且新鲜度要求不高的数据。
- 按需重新验证:基于事件(如表单提交)手动重新验证数据。按需重新验证可以使用基于标签或路径的方法一次性重新验证一组数据。适用于需要尽快显示最新数据的场景(例如无头 CMS 内容更新时)。
基于时间的重新验证
要按时间间隔重新验证数据,可以使用 fetch
的 next.revalidate
选项设置资源的缓存生命周期(以秒为单位)。
或者,要重新验证路由段中的所有 fetch
请求,可以使用段配置选项。
如果在静态渲染的路由中有多个 fetch 请求,且每个请求有不同的重新验证频率,则所有请求将使用最短的时间。对于动态渲染的路由,每个 fetch
请求将独立重新验证。
了解更多关于基于时间的重新验证。
按需重新验证
可以在路由处理器或服务端动作中通过路径 (revalidatePath
) 或缓存标签 (revalidateTag
) 按需重新验证数据。
Next.js 有一个缓存标签系统,用于跨路由使 fetch
请求失效。
- 使用
fetch
时,可以选择用一个或多个标签标记缓存条目。 - 然后,可以调用
revalidateTag
重新验证与该标签关联的所有条目。
例如,以下 fetch
请求添加了缓存标签 collection
:
如果使用路由处理器,应创建一个只有 Next.js 应用知道的密钥。此密钥用于防止未经授权的重新验证尝试。例如,可以通过以下 URL 结构访问路由(手动或通过 webhook):
或者,可以使用 revalidatePath
重新验证与路径关联的所有数据。
了解更多关于按需重新验证。
错误处理与重新验证
如果在尝试重新验证数据时抛出错误,将继续从缓存中提供上次成功生成的数据。在后续请求中,Next.js 将重试重新验证数据。
退出数据缓存
以下情况 fetch
请求不会被缓存:
fetch
请求中添加了cache: 'no-store'
。- 单个
fetch
请求中添加了revalidate: 0
选项。 fetch
请求位于使用POST
方法的路由处理器中。fetch
请求在使用了headers
或cookies
之后。- 使用了
const dynamic = 'force-dynamic'
路由段选项。 fetchCache
路由段选项配置为默认跳过缓存。fetch
请求使用了Authorization
或Cookie
标头,并且组件树中有未缓存的请求在其上方。
单个 fetch
请求
要为单个 fetch
请求退出缓存,可以将 fetch
的 cache
选项设置为 'no-store'
。这将在每次请求时动态获取数据。
查看所有可用的 cache
选项,请参阅 fetch
API 参考。
多个 fetch
请求
如果路由段(如布局或页面)中有多个 fetch
请求,可以使用段配置选项配置该段中所有数据请求的缓存行为。
例如,使用 const dynamic = 'force-dynamic'
将导致所有数据在请求时获取,并且该段将动态渲染。
段配置选项提供了广泛的列表,让您可以精细控制路由段的静态和动态行为。更多信息请参阅API 参考。
在服务端使用第三方库获取数据
如果您使用的第三方库不支持或不暴露 fetch
(例如数据库、CMS 或 ORM 客户端),可以使用路由段配置选项和 React 的 cache
函数配置这些请求的缓存和重新验证行为。
数据是否缓存取决于路由段是静态还是动态渲染。如果段是静态的(默认),请求的输出将作为路由段的一部分被缓存和重新验证。如果段是动态的,请求的输出将不会被缓存,并在段渲染时每次请求都会重新获取。
须知:
Next.js 正在开发一个 API
unstable_cache
,用于配置单个第三方请求的缓存和重新验证行为。
示例
在以下示例中:
revalidate
选项设置为3600
,意味着数据最多每小时缓存并重新验证一次。- React 的
cache
函数用于记忆化数据请求。
尽管 getItem
函数被调用了两次,但只会向数据库发送一次查询。
在客户端通过路由处理器获取数据
如果需要在客户端组件中获取数据,可以从客户端调用路由处理器。路由处理器在服务端执行并将数据返回给客户端。这在您不想向客户端暴露敏感信息(如 API 令牌)时非常有用。
请参阅路由处理器文档中的示例。
服务端组件与路由处理器
由于服务端组件在服务端渲染,您不需要从服务端组件调用路由处理器来获取数据。相反,可以直接在服务端组件中获取数据。
在客户端使用第三方库获取数据
您也可以使用第三方库(如 SWR 或 React Query)在客户端获取数据。这些库提供了自己的 API 用于记忆化请求、缓存、重新验证和变更数据。
未来 API:
use
是一个 React 函数,接受并处理由函数返回的 promise。目前不建议在客户端组件中包装fetch
使用use
,因为这可能会触发多次重新渲染。了解更多关于use
的信息,请参阅 React RFC。