錯誤處理

error.js 檔案約定讓您能優雅地處理嵌套路由中的意外運行時錯誤。

  • 自動將路由區段及其嵌套子項包裹在 React 錯誤邊界中。
  • 利用檔案系統層級結構來調整粒度,為特定區段建立客製化的錯誤 UI。
  • 將錯誤隔離在受影響的區段,同時保持應用程式其他部分正常運作。
  • 新增功能以嘗試從錯誤中恢復,無需完整頁面重新載入。

在路由區段內新增 error.js 檔案並導出 React 元件來建立錯誤 UI:

error.js 特殊檔案
'use client' // 錯誤元件必須是客戶端元件

import { useEffect } from 'react'

export default function Error({
  error,
  reset,
}: {
  error: Error & { digest?: string }
  reset: () => void
}) {
  useEffect(() => {
    // 將錯誤記錄到錯誤報告服務
    console.error(error)
  }, [error])

  return (
    <div>
      <h2>Something went wrong!</h2>
      <button
        onClick={
          // 嘗試透過重新渲染區段來恢復
          () => reset()
        }
      >
        Try again
      </button>
    </div>
  )
}

error.js 運作原理

error.js 運作方式
  • error.js 會自動建立一個 React 錯誤邊界包裹嵌套的子區段或 page.js 元件。
  • error.js 檔案導出的 React 元件會作為後備元件使用。
  • 如果在錯誤邊界內拋出錯誤,錯誤會被限制在該範圍內,並渲染後備元件。
  • 當後備錯誤元件處於活動狀態時,錯誤邊界上方的佈局會保持其狀態並維持可互動性,錯誤元件可以顯示從錯誤中恢復的功能。

從錯誤中恢復

有時錯誤的原因可能是暫時性的。在這些情況下,只需重試即可解決問題。

錯誤元件可以使用 reset() 函式提示使用者嘗試從錯誤中恢復。執行時,該函式會嘗試重新渲染錯誤邊界的內容。如果成功,後備錯誤元件將被重新渲染的結果取代。

'use client'

export default function Error({
  error,
  reset,
}: {
  error: Error & { digest?: string }
  reset: () => void
}) {
  return (
    <div>
      <h2>Something went wrong!</h2>
      <button onClick={() => reset()}>Try again</button>
    </div>
  )
}

嵌套路由

透過特殊檔案建立的 React 元件會以特定的嵌套層級結構渲染。

例如,一個包含 layout.jserror.js 檔案的兩個嵌套區段的路由,會以下列簡化的元件層級結構渲染:

嵌套錯誤元件層級結構

嵌套元件層級結構會影響嵌套路由中 error.js 檔案的行為:

  • 錯誤會向上冒泡到最近的父錯誤邊界。這意味著 error.js 檔案會處理其所有嵌套子區段的錯誤。透過在路由的嵌套資料夾中的不同層級放置 error.js 檔案,可以實現更細緻或更粗略的錯誤 UI。
  • error.js 邊界不會處理在同一區段的 layout.js 元件中拋出的錯誤,因為錯誤邊界是嵌套在該佈局元件內部。

處理佈局中的錯誤

error.js 邊界不會捕獲同一區段中 layout.jstemplate.js 元件拋出的錯誤。這種有意的層級結構確保在發生錯誤時,兄弟路由之間共享的重要 UI(例如導航)保持可見且可運作。

要處理特定佈局或模板中的錯誤,請在佈局的父區段中放置一個 error.js 檔案。

要處理根佈局或模板中的錯誤,請使用 error.js 的變體 global-error.js

處理根佈局中的錯誤

根目錄的 app/error.js 邊界不會捕獲根目錄 app/layout.jsapp/template.js 元件拋出的錯誤。

要專門處理這些根元件中的錯誤,請使用位於根 app 目錄中的 error.js 變體 app/global-error.js

與根目錄 error.js 不同,global-error.js 錯誤邊界會包裹整個應用程式,其後備元件在活動時會取代根佈局。因此,請注意 global-error.js 必須定義自己的 <html><body> 標籤。

global-error.js 是最不細緻的錯誤 UI,可視為整個應用程式的「全捕捉」錯誤處理。由於根元件通常較少動態變化,且其他 error.js 邊界會捕獲大多數錯誤,因此它不太常被觸發。

即使定義了 global-error.js,仍建議定義一個根目錄 error.js,其後備元件將在根佈局內部渲染,包含全域共享的 UI 和品牌標識。

'use client'

export default function GlobalError({
  error,
  reset,
}: {
  error: Error & { digest?: string }
  reset: () => void
}) {
  return (
    <html>
      <body>
        <h2>Something went wrong!</h2>
        <button onClick={() => reset()}>Try again</button>
      </body>
    </html>
  )
}

須知事項

  • global-error.js 僅在生產環境中啟用。在開發環境中,會顯示我們的錯誤覆蓋層。

處理伺服器錯誤

如果在伺服器元件中拋出錯誤,Next.js 會將 Error 物件(在生產環境中去除敏感錯誤資訊)作為 error 屬性轉發到最近的 error.js 檔案。

保護敏感錯誤資訊

在生產環境中,轉發到客戶端的 Error 物件僅包含通用的 messagedigest 屬性。

這是一種安全預防措施,避免將錯誤中可能包含的敏感細節洩露給客戶端。

message 屬性包含關於錯誤的通用訊息,而 digest 屬性包含自動產生的錯誤哈希值,可用於匹配伺服器端日誌中的相應錯誤。

在開發環境中,轉發到客戶端的 Error 物件會被序列化,並包含原始錯誤的 message,以便更容易除錯。

On this page