增量静态再生 (ISR)
增量静态再生 (ISR) 使你能够:
- 更新静态内容,而无需重建整个站点
- 通过为大多数请求提供预渲染的静态页面来减少服务器负载
- 确保自动将正确的
cache-control
标头添加到页面 - 处理大量内容页面,而无需漫长的
next build
时间
这是一个最小示例
interface Post {
id: string
title: string
content: string
}
// Next.js will invalidate the cache when a
// request comes in, at most once every 60 seconds.
export const revalidate = 60
// We'll prerender only the params from `generateStaticParams` at build time.
// If a request comes in for a path that hasn't been generated,
// Next.js will server-render the page on-demand.
export const dynamicParams = true // or false, to 404 on unknown paths
export async function generateStaticParams() {
const posts: Post[] = await fetch('https://api.vercel.app/blog').then((res) =>
res.json()
)
return posts.map((post) => ({
id: String(post.id),
}))
}
export default async function Page({
params,
}: {
params: Promise<{ id: string }>
}) {
const id = (await params).id
const post: Post = await fetch(`https://api.vercel.app/blog/${id}`).then(
(res) => res.json()
)
return (
<main>
<h1>{post.title}</h1>
<p>{post.content}</p>
</main>
)
}
以下是此示例的工作方式:
- 在
next build
期间,将生成所有已知的博客文章(在本示例中为 25 篇) - 对这些页面(例如
/blog/1
)的所有请求都将被缓存且是即时的 - 60 秒过后,下一个请求仍将显示缓存(过时)的页面
- 缓存失效,并在后台开始生成页面的新版本
- 成功生成后,Next.js 将显示并缓存更新后的页面
- 如果请求
/blog/26
,Next.js 将按需生成并缓存此页面
参考
路由段配置
函数
示例
基于时间的重新验证
这将获取并在 /blog
上显示博客文章列表。一小时后,此页面的缓存将在下次访问该页面时失效。然后,在后台,将使用最新的博客文章生成页面的新版本。
interface Post {
id: string
title: string
content: string
}
export const revalidate = 3600 // invalidate every hour
export default async function Page() {
const data = await fetch('https://api.vercel.app/blog')
const posts: Post[] = await data.json()
return (
<main>
<h1>Blog Posts</h1>
<ul>
{posts.map((post) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
</main>
)
}
我们建议设置较高的重新验证时间。例如,1 小时而不是 1 秒。如果需要更高的精度,请考虑使用按需重新验证。如果需要实时数据,请考虑切换到动态渲染。
使用 revalidatePath
的按需重新验证
对于更精确的重新验证方法,请使用 revalidatePath
函数按需使页面失效。
例如,在添加新文章后,将调用此服务器操作。无论你如何在服务器组件中使用 fetch
或连接到数据库来检索数据,这都将清除整个路由的缓存,并允许服务器组件获取新数据。
'use server'
import { revalidatePath } from 'next/cache'
export async function createPost() {
// Invalidate the /posts route in the cache
revalidatePath('/posts')
}
使用 revalidateTag
进行按需重新验证
对于大多数用例,建议优先重新验证整个路径。如果您需要更精细的控制,可以使用 revalidateTag
函数。例如,您可以标记单个 fetch
调用
export default async function Page() {
const data = await fetch('https://api.vercel.app/blog', {
next: { tags: ['posts'] },
})
const posts = await data.json()
// ...
}
如果您正在使用 ORM 或连接到数据库,则可以使用 unstable_cache
import { unstable_cache } from 'next/cache'
import { db, posts } from '@/lib/db'
const getCachedPosts = unstable_cache(
async () => {
return await db.select().from(posts)
},
['posts'],
{ revalidate: 3600, tags: ['posts'] }
)
export default async function Page() {
const posts = getCachedPosts()
// ...
}
然后,您可以在 服务器操作 (Server Actions) 或 路由处理程序 (Route Handler) 中使用 revalidateTag
'use server'
import { revalidateTag } from 'next/cache'
export async function createPost() {
// Invalidate all data tagged with 'posts' in the cache
revalidateTag('posts')
}
处理未捕获的异常
如果在尝试重新验证数据时抛出错误,则将继续从缓存中提供上次成功生成的数据。在后续的请求中,Next.js 将重试重新验证数据。了解更多关于错误处理的信息。
自定义缓存位置
缓存和重新验证页面(使用增量静态再生)使用相同的共享缓存。当部署到 Vercel时,ISR 缓存会自动持久化到持久存储。
当自托管时,ISR 缓存会存储到 Next.js 服务器上的文件系统(磁盘)中。当使用 Pages Router 和 App Router 进行自托管时,这会自动生效。
如果您想将缓存的页面和数据持久化到持久存储,或在 Next.js 应用程序的多个容器或实例之间共享缓存,您可以配置 Next.js 缓存位置。了解更多。
故障排除
调试本地开发中的缓存数据
如果您正在使用 fetch
API,您可以添加额外的日志记录以了解哪些请求被缓存或未缓存。了解更多关于 logging
选项的信息。
module.exports = {
logging: {
fetches: {
fullUrl: true,
},
},
}
验证正确的生产环境行为
要验证您的页面在生产环境中是否被正确缓存和重新验证,您可以在本地通过运行 next build
,然后运行 next start
来启动生产环境的 Next.js 服务器进行测试。
这将允许您测试 ISR 行为,使其如同在生产环境中工作一样。为了进一步调试,请将以下环境变量添加到您的 .env
文件中
NEXT_PRIVATE_DEBUG_CACHE=1
这将使 Next.js 服务器控制台记录 ISR 缓存命中和未命中。您可以检查输出,以查看哪些页面在 next build
期间生成,以及页面如何在按需访问路径时更新。
注意事项
- 仅在使用 Node.js 运行时(默认)时才支持 ISR。
- 创建静态导出 (Static Export)时不支持 ISR。
- 如果您在静态渲染的路由中有多个
fetch
请求,并且每个请求都有不同的revalidate
频率,则 ISR 将使用最短的时间。但是,这些重新验证频率仍然会被数据缓存 (Data Cache) 所遵守。 - 如果路由上使用的任何
fetch
请求的revalidate
时间为0
,或者显式设置为no-store
,则该路由将动态渲染 (dynamically rendered)。 - 中间件 (Middleware) 不会为按需 ISR 请求执行,这意味着中间件中的任何路径重写或逻辑都不会被应用。请确保您正在重新验证确切的路径。例如,
/post/1
而不是重写的/post-1
。
版本历史
版本 | 变更 |
---|---|
v14.1.0 | 自定义 cacheHandler 已稳定。 |
v13.0.0 | 引入 App Router。 |
v12.2.0 | Pages Router:按需 ISR 已稳定 |
v12.0.0 | Pages Router:添加了 Bot 感知 ISR 回退。 |
v9.5.0 | Pages Router:引入了稳定的 ISR。 |
这篇文章对您有帮助吗?