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:
import type { GetStaticPaths, GetStaticProps } from 'next'
interface Post {
id: string
title: string
content: string
}
interface Props {
post: Post
}
export const getStaticPaths: GetStaticPaths = async () => {
const posts = await fetch('https://api.vercel.app/blog').then((res) =>
res.json()
)
const paths = posts.map((post: Post) => ({
params: { id: String(post.id) },
}))
// We'll prerender only these paths at build time.
// { fallback: 'blocking' } will server-render pages
// on-demand if the path doesn't exist.
return { paths, fallback: false }
}
export const getStaticProps: GetStaticProps<Props> = async ({
params,
}: {
params: { id: string }
}) => {
const post = await fetch(`https://api.vercel.app/blog/${params.id}`).then(
(res) => res.json()
)
return {
props: { post },
// Next.js will invalidate the cache when a
// request comes in, at most once every 60 seconds.
revalidate: 60,
}
}
export default function Page({ post }: Props) {
return (
<main>
<h1>{post.title}</h1>
<p>{post.content}</p>
</main>
)
}
此示例的工作原理如下:
¥Here's how this example works:
在
next build
期间,将生成所有已知博客文章(此示例中有 25 篇)¥During
next build
, all known blog posts are generated (there are 25 in this example)对这些页面(例如
/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 show the cached (stale) page
缓存失效,新版本的页面开始在后台生成
¥The cache is invalidated and a new version of the page begins generating in the background
成功生成后,Next.js 将显示并缓存更新的页面
¥Once generated successfully, Next.js will display and cache the updated page
如果请求
/blog/26
,Next.js 将按需生成并缓存此页面¥If
/blog/26
is requested, Next.js will generate and cache this page on-demand
参考
¥Reference
函数
¥Functions
示例
¥Examples
使用 res.revalidate()
进行按需验证
¥On-demand validation with res.revalidate()
为了更精确地进行重新验证,请使用 res.revalidate
从 API 路由按需生成新页面。
¥For a more precise method of revalidation, use res.revalidate
to generate a new page on-demand from an API Router.
例如,可以在 /api/revalidate?secret=<token>
调用此 API 路由来重新验证给定的博客文章。创建一个只有 Next.js 应用知道的密钥令牌。此密钥将用于防止未经授权访问重新验证 API 路由。
¥For example, this API Route can be called at /api/revalidate?secret=<token>
to revalidate a given blog post. Create a secret token only known by your Next.js app. This secret will be used to prevent unauthorized access to the revalidation API Route.
import type { NextApiRequest, NextApiResponse } from 'next'
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
// Check for secret to confirm this is a valid request
if (req.query.secret !== process.env.MY_SECRET_TOKEN) {
return res.status(401).json({ message: 'Invalid token' })
}
try {
// This should be the actual path not a rewritten path
// e.g. for "/posts/[id]" this should be "/posts/1"
await res.revalidate('/posts/1')
return res.json({ revalidated: true })
} catch (err) {
// If there was an error, Next.js will continue
// to show the last successfully generated page
return res.status(500).send('Error revalidating')
}
}
如果你正在使用按需重新验证,则无需在 getStaticProps
中指定 revalidate
时间。Next.js 将使用 false
的默认值(不重新验证),并且仅在调用 res.revalidate()
时按需重新验证页面。
¥If you are using on-demand revalidation, you do not need to specify a revalidate
time inside of getStaticProps
. Next.js will use the default value of false
(no revalidation) and only revalidate the page on-demand when res.revalidate()
is called.
处理未捕获的异常
¥Handling uncaught exceptions
如果 getStaticProps
在处理后台再生时出现错误,或者你手动抛出错误,则上次成功生成的页面将继续显示。在下一个后续请求中,Next.js 将重试调用 getStaticProps
。
¥If there is an error inside getStaticProps
when handling background regeneration, or you manually throw an error, the last successfully generated page will continue to show. On the next subsequent request, Next.js will retry calling getStaticProps
.
import type { GetStaticProps } from 'next'
interface Post {
id: string
title: string
content: string
}
interface Props {
post: Post
}
export const getStaticProps: GetStaticProps<Props> = async ({
params,
}: {
params: { id: string }
}) => {
// If this request throws an uncaught error, Next.js will
// not invalidate the currently shown page and
// retry getStaticProps on the next request.
const res = await fetch(`https://api.vercel.app/blog/${params.id}`)
const post: Post = await res.json()
if (!res.ok) {
// If there is a server error, you might want to
// throw an error instead of returning so that the cache is not updated
// until the next successful request.
throw new Error(`Failed to fetch posts, received status ${res.status}`)
}
return {
props: { post },
// Next.js will invalidate the cache when a
// request comes in, at most once every 60 seconds.
revalidate: 60,
}
}
自定义缓存位置
¥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:
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.
中间件不会针对按需 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 介绍。 |