如何實現增量靜態再生 (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
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>
)
}此示例的工作方式如下
- 在
next build期間,所有已知部落格文章都會生成 - 對這些頁面(例如
/blog/1)發出的所有請求都會被快取並立即響應 - 60 秒過後,下一個請求仍將返回快取的(現在已過期)頁面
- 快取失效,並在後臺開始生成頁面的新版本
- 成功生成後,下一個請求將返回更新後的頁面並將其快取,以供後續請求使用
- 如果請求
/blog/26並且它存在,則頁面將按需生成。此行為可以透過使用不同的 dynamicParams 值來更改。但是,如果帖子不存在,則返回 404。
參考
路由段配置
函式
示例
基於時間重驗證
這會在 /blog 上獲取並顯示部落格文章列表。一個小時過後,下一個訪問者仍會立即收到頁面快取(過期)版本以獲得快速響應。同時,Next.js 會在後臺觸發新版本的再生。一旦新版本成功生成,它會替換快取版本,後續訪問者將收到更新後的內容。
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 還是連線到資料庫,這都將使整個路由的快取失效。對該路由的下一個請求將觸發重新生成並提供最新資料,然後該資料將快取以供後續請求使用。
注意:
revalidatePath使快取條目失效,但重新生成發生在下一個請求上。如果您希望立即主動重新生成快取條目,而不是等待下一個請求,您可以使用 Pages 路由res.revalidate方法。我們正在努力新增新方法,以提供 App Router 的主動重新生成功能。
'use server'
import { revalidatePath } from 'next/cache'
export async function createPost() {
// Invalidate the cache for the /posts route
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()
// ...
}然後您可以在伺服器操作或路由處理程式中使用 revalidateTag
'use server'
import { revalidateTag } from 'next/cache'
export async function createPost() {
// Invalidate all data tagged with 'posts'
revalidateTag('posts')
}處理未捕獲的異常
如果在嘗試重新驗證資料時發生錯誤,則上次成功生成的資料將繼續從快取中提供。在下一個請求中,Next.js 將重試重新驗證資料。瞭解更多關於錯誤處理的資訊。
自定義快取位置
如果您希望將快取頁面和資料持久化到持久儲存,或在 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 期間生成了哪些頁面,以及在按需訪問路徑時頁面如何更新。
注意事項
- ISR 僅在使用 Node.js 執行時(預設)時支援。
- 建立靜態匯出時不支援 ISR。
- 如果靜態渲染路由中有多個
fetch請求,並且每個請求都有不同的revalidate頻率,則將使用最低時間作為 ISR。但是,這些重新驗證頻率仍將由資料快取遵循。 - 如果路由上使用的任何
fetch請求的revalidate時間為0或顯式no-store,則該路由將動態渲染。 - 代理不會為按需 ISR 請求執行,這意味著代理中的任何路徑重寫或邏輯都不會應用。請確保您正在重新驗證精確的路徑。例如,
/post/1而不是重寫的/post-1。
平臺支援
| 部署選項 | 支援 |
|---|---|
| Node.js 伺服器 | 是 |
| Docker 容器 | 是 |
| 靜態匯出 | 否 |
| 介面卡 | 平臺特定 |
瞭解如何在自託管 Next.js 時配置 ISR。
版本歷史
| 版本 | 更改 |
|---|---|
v14.1.0 | 自定義 cacheHandler 已穩定。 |
v13.0.0 | App Router 已引入。 |
v12.2.0 | Pages Router:按需 ISR 已穩定 |
v12.0.0 | Pages Router:添加了機器人感知 ISR 回退。 |
v9.5.0 | Pages Router:引入了穩定的 ISR。 |
這有幫助嗎?