遞增靜態再生 (ISR)
遞增靜態再生 (ISR) 讓您能夠:
- 更新靜態內容,無需重建整個網站
- 透過為大多數請求提供預先渲染的靜態頁面,來減少伺服器負載
- 確保正確的
cache-control
標頭自動新增至頁面 - 處理大量內容頁面,而不會有長時間的
next build
建置時間
以下是一個最小範例
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>
)
}
以下說明此範例的運作方式:
- 在
next build
期間,會產生所有已知的部落格文章(在此範例中有 25 篇) - 對這些頁面(例如
/blog/1
)的所有請求都會被快取並立即顯示 - 經過 60 秒後,下一個請求仍會顯示快取的(過時)頁面
- 快取失效,並開始在背景中產生新版本的頁面
- 成功產生後,Next.js 將顯示並快取更新後的頁面
- 如果請求
/blog/26
,Next.js 將隨需產生並快取此頁面
參考資料
函式
範例
使用 res.revalidate()
隨需驗證
若要取得更精確的重新驗證方法,請使用 res.revalidate
從 API Router 隨需產生新頁面。
例如,可以呼叫此 API 路由 /api/revalidate?secret=<token>
以重新驗證指定的部落格文章。建立只有您的 Next.js 應用程式知道的密碼權杖。此密碼將用於防止未經授權存取重新驗證 API 路由。
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()
時隨需重新驗證頁面。
處理未捕獲的例外
如果在處理背景重新產生時,getStaticProps
內部發生錯誤,或者您手動拋出錯誤,則最後成功產生的頁面將繼續顯示。在下一個後續請求中,Next.js 將重試呼叫 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,
}
}
自訂快取位置
快取和重新驗證頁面(使用遞增靜態再生)使用相同的共用快取。當部署到 Vercel時,ISR 快取會自動持久儲存到耐用儲存空間。
當自行託管時,ISR 快取會儲存在 Next.js 伺服器上的檔案系統(磁碟上)。當使用 Pages 和 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。
- 建立靜態匯出時,不支援 ISR。
- 中介軟體不會針對隨需 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-aware ISR 後備。 |
v9.5.0 | Pages Router:引入穩定的 ISR。 |
這有幫助嗎?