跳至內容
頁面路由器...資料擷取增量靜態再生 (ISR)

增量靜態重新產生 (ISR)

範例

Next.js 讓您可以在建置網站建立或更新靜態頁面。增量靜態再生 (ISR) 讓您可以在逐頁的基礎上使用靜態產生,而無需重建整個網站。透過 ISR,您可以在擴充到數百萬個頁面的同時,保留靜態的優點。

須知edge 執行時期 目前與 ISR 不相容,不過您可以透過手動設定 cache-control 標頭來利用 stale-while-revalidate

若要使用 ISR,請將 revalidate 屬性新增至 getStaticProps

function Blog({ posts }) {
  return (
    <ul>
      {posts.map((post) => (
        <li key={post.id}>{post.title}</li>
      ))}
    </ul>
  )
}
 
// This function gets called at build time on server-side.
// It may be called again, on a serverless function, if
// revalidation is enabled and a new request comes in
export async function getStaticProps() {
  const res = await fetch('https://.../posts')
  const posts = await res.json()
 
  return {
    props: {
      posts,
    },
    // Next.js will attempt to re-generate the page:
    // - When a request comes in
    // - At most once every 10 seconds
    revalidate: 10, // In seconds
  }
}
 
// This function gets called at build time on server-side.
// It may be called again, on a serverless function, if
// the path has not been generated.
export async function getStaticPaths() {
  const res = await fetch('https://.../posts')
  const posts = await res.json()
 
  // Get the paths we want to pre-render based on posts
  const paths = posts.map((post) => ({
    params: { id: post.id },
  }))
 
  // We'll pre-render only these paths at build time.
  // { fallback: 'blocking' } will server-render pages
  // on-demand if the path doesn't exist.
  return { paths, fallback: 'blocking' }
}
 
export default Blog

當對在建置時預先呈現的頁面提出請求時,它最初會顯示快取頁面。

  • 在初始請求後和 10 秒前對頁面的任何請求也會快取並即時處理。
  • 在 10 秒的視窗後,下一個請求仍會顯示快取(過時)的頁面
  • Next.js 會在背景中觸發頁面重新產生。
  • 頁面產生成功後,Next.js 會使快取失效並顯示已更新的頁面。如果背景重新產生失敗,舊頁面仍會保持不變。

當對尚未產生的路徑提出請求時,Next.js 會在第一次請求時對頁面進行伺服器端渲染。後續請求會從快取提供靜態檔案。Vercel 上的 ISR 會在全球範圍內保留快取並處理回滾

須知:檢查上游資料提供者是否預設啟用快取。您可能需要停用(例如 useCdn: false),否則重新驗證將無法提取最新資料來更新 ISR 快取。當 CDN(針對被請求的端點)傳回 Cache-Control 標頭時,快取可能會發生在 CDN 上。

依需求重新驗證

如果您將 revalidate 時間設定為 60,所有訪客都會看到您網站的相同已產生版本,時間為一分鐘。使快取失效的唯一方法是有人在經過一分鐘後造訪該頁面。

v12.2.0 開始,Next.js 支援依需求增量靜態重新產生,以手動清除特定頁面的 Next.js 快取。這讓您在下列情況下更新網站時更輕鬆:

  • 您的無頭 CMS 中的內容已建立或更新
  • 電子商務的元資料已變更(價格、說明、類別、評論等)

getStaticProps 內,您不需要指定 revalidate 來使用依需求重新驗證。如果省略 revalidate,Next.js 會使用預設值 false(不重新驗證),且僅在呼叫 revalidate() 時依需求重新驗證頁面。

須知中介軟體不會對依需求 ISR 請求執行。相反地,在您想要重新驗證的精確路徑上呼叫 revalidate()。例如,如果您有 pages/blog/[slug].js 和從 /post-1 -> /blog/post-1 的重寫,您需要呼叫 res.revalidate('/blog/post-1')

使用按需重新驗證

首先,建立一個只有 Next.js 應用程式知道的機密權杖。這個機密權杖會用來防止未經授權存取重新驗證 API 路由。你可以使用以下 URL 結構手動或透過網路掛勾存取路由

終端機
https://<your-site.com>/api/revalidate?secret=<token>

接著,將機密權杖新增為應用程式的環境變數。最後,建立重新驗證 API 路由

pages/api/revalidate.js
export default async function handler(req, res) {
  // 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 "/blog/[slug]" this should be "/blog/post-1"
    await res.revalidate('/path-to-revalidate')
    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')
  }
}

查看我們的示範以查看按需重新驗證的實際運作並提供回饋。

在開發期間測試按需 ISR

使用 next dev 本機執行時,每次要求都會呼叫 getStaticProps。要驗證你的按需 ISR 設定正確無誤,你需要建立一個正式版本並啟動正式伺服器

終端機
$ next build
$ next start

接著,你可以確認靜態頁面已成功重新驗證。

錯誤處理和重新驗證

如果處理背景重新產生時 getStaticProps 內部發生錯誤,或你手動擲回錯誤,最後成功產生的頁面將會繼續顯示。在接下來的後續要求中,Next.js 會重試呼叫 getStaticProps

export async function getStaticProps() {
  // 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://.../posts')
  const posts = 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}`)
  }
 
  // If the request was successful, return the posts
  // and revalidate every 10 seconds.
  return {
    props: {
      posts,
    },
    revalidate: 10,
  }
}

自架設 ISR

增量靜態再生 (ISR) 在使用 next start 時,會在 自架設 Next.js 網站 中開箱即用。

深入了解 自架設 Next.js

版本歷程

版本變更
v14.1.0自訂 cacheHandler 已穩定。
v12.2.0依需求 ISR 已穩定
v12.1.0新增依需求 ISR(測試版)。
v12.0.0新增機器人感知 ISR 回退
v9.5.0新增基本路徑。