介紹/指南/ISR

如何實作增量靜態再生 (ISR)

範例

增量靜態再生 (ISR) 讓您能夠:

  • 更新靜態內容而無需重建整個網站
  • 透過提供預渲染的靜態頁面來減少伺服器負載
  • 確保自動為頁面添加正確的 cache-control 標頭
  • 處理大量內容頁面而無需長時間的 next build

以下是一個最小範例:

interface Post {
  id: string
  title: string
  content: string
}

// Next.js 會在請求進來時使快取失效
// 最多每 60 秒一次
export const revalidate = 60

// 我們只會在建置時預渲染來自 `generateStaticParams` 的參數
// 如果請求的路徑尚未生成
// Next.js 會按需伺服器渲染該頁面
export const dynamicParams = true // 或設為 false,以在未知路徑回傳 404

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>
  )
}

這個範例的運作方式如下:

  1. next build 期間,所有已知的部落格文章會被生成(此範例中有 25 篇)
  2. 對這些頁面的所有請求(例如 /blog/1)會被快取且立即回應
  3. 60 秒過後,下一個請求仍會顯示快取的(過期)頁面
  4. 快取失效後,新版本的頁面會在背景開始生成
  5. 成功生成後,Next.js 會顯示並快取更新後的頁面
  6. 如果請求 /blog/26,Next.js 會按需生成並快取此頁面

參考資料

路由區段配置

函式

範例

基於時間的重新驗證

這會在 /blog 上取得並顯示部落格文章列表。一小時後,此頁面的快取會在下次訪問時失效。然後,在背景中,會使用最新的部落格文章生成頁面的新版本。

interface Post {
  id: string
  title: string
  content: string
}

export const revalidate = 3600 // 每小時失效一次

export default async function Page() {
  const data = await fetch('https://api.vercel.app/blog')
  const posts: Post[] = await data.json()
  return (
    <main>
      <h1>部落格文章</h1>
      <ul>
        {posts.map((post) => (
          <li key={post.id}>{post.title}</li>
        ))}
      </ul>
    </main>
  )
}

我們建議設定較高的重新驗證時間。例如,1 小時而非 1 秒。如果您需要更精確的控制,請考慮使用按需重新驗證。如果您需要即時資料,請考慮切換到動態渲染

使用 revalidatePath 進行按需重新驗證

對於更精確的重新驗證方法,可以使用 revalidatePath 函式按需使頁面失效。

例如,這個伺服器動作會在新增文章後被呼叫。無論您在伺服器元件中使用 fetch 或連接到資料庫來取得資料,這都會清除整個路由的快取,並允許伺服器元件取得最新資料。

'use server'

import { revalidatePath } from 'next/cache'

export async function createPost() {
  // 使快取中的 /posts 路由失效
  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() {
  // 使快取中標記為 'posts' 的所有資料失效
  revalidateTag('posts')
}

處理未捕獲的例外

如果在嘗試重新驗證資料時拋出錯誤,則會繼續從快取中提供最後成功生成的資料。在下一個後續請求中,Next.js 會重試重新驗證資料。了解更多關於錯誤處理的資訊

自訂快取位置

如果您想將快取的頁面和資料持久化到持久儲存,或者在 Next.js 應用程式的多個容器或實例之間共享快取,可以配置 Next.js 快取位置。了解更多

疑難排解

在本地開發中除錯快取資料

如果您使用 fetch API,可以添加額外的日誌記錄來了解哪些請求被快取或未快取。了解更多關於 logging 選項的資訊

next.config.js
module.exports = {
  logging: {
    fetches: {
      fullUrl: true,
    },
  },
}

驗證正確的生產環境行為

若要驗證您的頁面在生產環境中是否正確快取及重新驗證,可以在本地執行 next build 後再執行 next start 來運行 Next.js 的生產環境伺服器。

這將讓您測試 ISR (Incremental Static Regeneration) 行為在生產環境中的運作方式。如需進一步除錯,請在 .env 檔案中加入以下環境變數:

.env
NEXT_PRIVATE_DEBUG_CACHE=1

這會讓 Next.js 伺服器在主控台記錄 ISR 快取命中與未命中的情況。您可以檢查輸出內容,查看哪些頁面是在 next build 時生成的,以及當路徑被按需存取時頁面是如何更新的。

注意事項

  • ISR 僅在使用 Node.js 運行環境 (預設) 時支援。
  • 建立 靜態匯出 (Static Export) 時不支援 ISR。
  • 如果在靜態渲染的路由中有多個 fetch 請求,且每個請求有不同的 revalidate 頻率,ISR 將使用最短的時間。然而,這些重新驗證頻率仍會受到 資料快取 (Data Cache) 的尊重。
  • 如果路由中使用的任何 fetch 請求的 revalidate 時間為 0,或明確設定為 no-store,該路由將被 動態渲染 (dynamically rendered)
  • 中介軟體 (Middleware) 不會在按需 ISR 請求時執行,這意味著任何路徑重寫或中介軟體中的邏輯都不會生效。請確保您重新驗證的是確切路徑。例如 /post/1 而非重寫後的 /post-1

平台支援

部署選項是否支援
Node.js 伺服器
Docker 容器
靜態匯出
轉接器 (Adapters)依平台而定

了解如何在使用 Next.js 自架時 設定 ISR

版本歷史

版本變更
v14.1.0自訂 cacheHandler 功能穩定。
v13.0.0引入 App Router。
v12.2.0Pages Router: 按需 ISR 功能穩定。
v12.0.0Pages Router: 新增 Bot-aware ISR 回退機制
v9.5.0Pages Router: 引入穩定的 ISR 功能