主题
ISR
增量静态再生 (ISR) 使你能够:
¥Incremental Static Regeneration (ISR) enables you to:
无需重建整个站点即可更新静态内容
¥Update static content without rebuilding the entire site
通过为大多数请求提供预渲染的静态页面来减少服务器负载
¥Reduce server load by serving prerendered, static pages for most requests
确保将正确的
cache-control
标头自动添加到页面¥Ensure proper
cache-control
headers are automatically added to pages无需长时间
next build
即可处理大量内容页面¥Handle large amounts of content pages without long
next build
times
这是一个最小示例:
¥Here's a minimal example:
tsx
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
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
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>
)
}
此示例的工作原理如下:
¥Here's how this example works:
在
next build
期间,会生成所有已知的博客文章。¥During
next build
, all known blog posts are generated对这些页面(例如
/blog/1
)的所有请求都已缓存并即时执行¥All requests made to these pages (e.g.
/blog/1
) are cached and instantaneous60 秒后,下一个请求仍将返回缓存的(现已过时的)页面
¥After 60 seconds has passed, the next request will still return the cached (now stale) page
缓存失效,新版本的页面开始在后台生成
¥The cache is invalidated and a new version of the page begins generating in the background
成功生成后,下一个请求将返回更新后的页面并将其缓存以供后续请求使用。
¥Once generated successfully, the next request will return the updated page and cache it for subsequent requests
如果请求了
/blog/26
,并且它存在,则页面将按需生成。可以使用不同的 dynamicParams 值来更改此行为。但是,如果帖子不存在,则会返回 404。¥If
/blog/26
is requested, and it exists, the page will be generated on-demand. This behavior can be changed by using a different dynamicParams value. However, if the post does not exist, then 404 is returned.
参考
¥Reference
路由段配置
¥Route segment config
函数
¥Functions
示例
¥Examples
基于时间的重新验证
¥Time-based revalidation
这将获取并显示 /blog 上的博客文章列表。一小时后,下一个访问者仍将立即收到页面的缓存(过时)版本,以便快速响应。同时,Next.js 会在后台触发新版本的重新生成。成功生成新版本后,它将替换缓存的版本,后续访问者将收到更新后的内容。
¥This fetches and displays a list of blog posts on /blog. After an hour has passed, the next visitor will still receive the cached (stale) version of the page immediately for a fast response. Simultaneously, Next.js triggers regeneration of a fresh version in the background. Once the new version is successfully generated, it replaces the cached version, and subsequent visitors will receive the updated content.
tsx
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 秒。如果你需要更高的精度,请考虑使用按需重新验证。如果你需要实时数据,请考虑切换到 动态渲染。
¥We recommend setting a high revalidation time. For instance, 1 hour instead of 1 second. If you need more precision, consider using on-demand revalidation. If you need real-time data, consider switching to dynamic rendering.
使用 revalidatePath
进行按需重新验证
¥On-demand revalidation with revalidatePath
要获得更精确的重新验证方法,请使用 revalidatePath
函数按需使缓存页面失效。
¥For a more precise method of revalidation, invalidate cached pages on-demand with the revalidatePath
function.
例如,添加新帖子后将调用此服务器操作。无论你如何在服务器组件中检索数据(使用 fetch
还是连接到数据库),这都会使整个路由的缓存失效。对该路由的下一个请求将触发重新生成并提供新数据,这些数据随后将被缓存以供后续请求使用。
¥For example, this Server Action would get called after adding a new post. Regardless of how you retrieve your data in your Server Component, either using fetch
or connecting to a database, this will invalidate the cache for the entire route. The next request to that route will trigger regeneration and serve fresh data, which will then be cached for subsequent requests.
注意:
revalidatePath
会使缓存条目失效,但会在下次请求时重新生成缓存。如果你想立即重新生成缓存条目,而不是等待下一个请求,可以使用 Pages 路由的res.revalidate
方法。我们正在努力添加新方法,为应用路由提供即时再生功能。¥Note:
revalidatePath
invalidates the cache entries but regeneration happens on the next request. If you want to eagerly regenerate the cache entry immediately instead of waiting for the next request, you can use the Pages routerres.revalidate
method. We're working on adding new methods to provide eager regeneration capabilities for the App Router.
ts
'use server'
import { revalidatePath } from 'next/cache'
export async function createPost() {
// Invalidate the cache for the /posts route
revalidatePath('/posts')
}
¥View a demo and explore the source code.
使用 revalidateTag
进行按需重新验证
¥On-demand revalidation with revalidateTag
对于大多数用例,最好重新验证整个路径。如果你需要更精细的控制,你可以使用 revalidateTag
函数。例如,你可以标记单个 fetch
调用:
¥For most use cases, prefer revalidating entire paths. If you need more granular control, you can use the revalidateTag
function. For example, you can tag individual fetch
calls:
tsx
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
:
¥If you are using an ORM or connecting to a database, you can use unstable_cache
:
tsx
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()
// ...
}
然后,你可以在 服务器操作 或 路由处理程序 中使用 revalidateTag
:
¥You can then use revalidateTag
in a Server Actions or Route Handler:
ts
'use server'
import { revalidateTag } from 'next/cache'
export async function createPost() {
// Invalidate all data tagged with 'posts'
revalidateTag('posts')
}
处理未捕获的异常
¥Handling uncaught exceptions
如果在尝试重新验证数据时抛出错误,则将继续从缓存中提供最后成功生成的数据。在下一个后续请求中,Next.js 将重试重新验证数据。了解有关错误处理的更多信息。
¥If an error is thrown while attempting to revalidate data, the last successfully generated data will continue to be served from the cache. On the next subsequent request, Next.js will retry revalidating the data. Learn more about error handling.
自定义缓存位置
¥Customizing the cache location
如果你想要将缓存的页面和数据持久保存到持久存储,或者在 Next.js 应用的多个容器或实例之间共享缓存,你可以配置 Next.js 缓存位置。了解更多。
¥You can configure the Next.js cache location if you want to persist cached pages and data to durable storage, or share the cache across multiple containers or instances of your Next.js application. Learn more.
故障排除
¥Troubleshooting
在本地开发中调试缓存数据
¥Debugging cached data in local development
如果你使用 fetch
API,则可以添加其他日志记录以了解哪些请求已缓存或未缓存。了解有关 logging
选项的更多信息。
¥If you are using the fetch
API, you can add additional logging to understand which requests are cached or uncached. Learn more about the logging
option.
验证正确的生产行为
¥Verifying correct production behavior
要验证你的页面在生产中是否已正确缓存和重新验证,你可以通过运行 next build
然后运行 next start
来运行生产 Next.js 服务器,在本地进行测试。
¥To verify your pages are cached and revalidated correctly in production, you can test locally by running next build
and then next start
to run the production Next.js server.
这将允许你测试 ISR 行为,就像它在生产环境中一样。为了进一步调试,请将以下环境变量添加到你的 .env
文件中:
¥This will allow you to test ISR behavior as it would work in a production environment. For further debugging, add the following environment variable to your .env
file:
bash
NEXT_PRIVATE_DEBUG_CACHE=1
这将使 Next.js 服务器控制台记录 ISR 缓存命中和未命中。你可以检查输出以查看在 next build
期间生成了哪些页面,以及在按需访问路径时如何更新页面。
¥This will make the Next.js server console log ISR cache hits and misses. You can inspect the output to see which pages are generated during next build
, as well as how pages are updated as paths are accessed on-demand.
注意事项
¥Caveats
仅在使用 Node.js 运行时(默认)时才支持 ISR。
¥ISR is only supported when using the Node.js runtime (default).
创建 静态导出 时不支持 ISR。
¥ISR is not supported when creating a Static Export.
如果你在静态渲染的路由中有多个
fetch
请求,并且每个请求都有不同的revalidate
频率,则将使用最短的时间进行 ISR。但是,数据缓存 仍将尊重这些重新验证频率。¥If you have multiple
fetch
requests in a statically rendered route, and each has a differentrevalidate
frequency, the lowest time will be used for ISR. However, those revalidate frequencies will still be respected by the Data Cache.如果在路由上使用的任何
fetch
请求的revalidate
时间为0
,或显式no-store
,则路由将为 动态渲染。¥If any of the
fetch
requests used on a route have arevalidate
time of0
, or an explicitno-store
, the route will be dynamically rendered.中间件不会针对按需 ISR 请求执行,这意味着中间件中的任何路径重写或逻辑都不会应用。确保你正在重新验证确切的路径。例如,
/post/1
而不是重写的/post-1
。¥Middleware won't be executed for on-demand ISR requests, meaning any path rewrites or logic in Middleware will not be applied. Ensure you are revalidating the exact path. For example,
/post/1
instead of a rewritten/post-1
.
平台支持
¥Platform Support
部署选项 | 支持 |
---|---|
Node.js 服务器 | 是 |
Docker 容器 | 是 |
静态导出 | 否 |
适配器 | 平台相关 |
了解如何在自托管 Next.js 时进行 配置 ISR。
¥Learn how to configure ISR when self-hosting Next.js.
版本历史记录
¥Version history
版本 | 更改 |
---|---|
v14.1.0 | 自定义 cacheHandler 是稳定的。 |
v13.0.0 | 引入 App Router。 |
v12.2.0 | 页面路由:按需 ISR 稳定 |
v12.0.0 | 页面路由:机器人感知 ISR 后备 已添加。 |
v9.5.0 | 页面路由:稳定的 ISR 介绍。 |