Error Handling

error.js文件允许你在嵌套路由中处理意外运行的 error。

  • 使用React Error Boundar自动包裹 route segment 以及它的子组件。
  • 可以使用文件系统的层次结构来调整粒度,创建针对特定 segment 的 error UI。
  • 将 error 隔离到受影响的 segment,同时保持应用程序的其余部分正常工作。
  • 可以增加功能以在发生错误时尝试恢复,而无需刷新页面

通过在 route segment 里创建 error.js 并导出一个 React Component 来创建 error UI。

error.js special file

typescript
1'use client' // Error components must be Client Components
2
3import { useEffect } from 'react'
4
5export default function Error({ error, reset }: { error: Error; reset: () => void }) {
6  useEffect(() => {
7    // Log the error to an error reporting service
8    console.error(error)
9  }, [error])
10
11  return (
12    <div>
13      <h2>Something went wrong!</h2>
14      <button
15        onClick={
16          // Attempt to recover by trying to re-render the segment
17          () => reset()
18        }
19      >
20        Try again
21      </button>
22    </div>
23  )
24}

error.js怎样工作

How error.js works

  1. error.js自动创建一个包裹子 segment 或者 page.js的 React Error Boundary
  2. 从 error.js 中导出的 React 组件会被当做 fallback 使用
  3. 如果一个错误在 error Boundary 中被 throw 出来,fallback 会被渲染出来
  4. 当 fallback 组件处于活动状态时,error Boundary上方的 layout 将保持其状态并保持可交互性,而 error 组件可以通过 reset 以从错误中恢复。

从错误中恢复

引起错误的原因可能是暂时的,在下面的例子中,只需再试一次即可解决问题。

error 组件可以使用reset()函数提示用户尝试从错误中恢复。执行时,该函数将尝试重新呈现error Boundary 的内容。如果成功,则 fallback 组件将被重新渲染的结果所替换。

jsx
1'use client'
2
3export default function Error({
4  error,
5  reset,
6}: {
7  error: Error
8  reset: () => void
9}) {
10  return (
11    <div>
12      <h2>Something went wrong!</h2>
13      <button onClick={() => reset()}>Try again</button>
14    </div>
15  )
16}

嵌套路由

下面展示嵌套路由时,react 组件的嵌套结构:

Nested Error Component Hierarchy

  • 错误会冒泡到最近的 ErrorBoundary。这意味着 error.js 文件将处理所有在嵌套子 segments 内的错误。 通过在路由的嵌套文件夹中放置不同级别的 error.js 文件能够实现更精细的错误提示 UI。
  • error.js 不能处理同一 segment 中 layout 组件抛出的错误,因为它被嵌套在 layout 内。

在 layout 中处理错误

error.js不能捕捉到在同一 segment 级别下的layout.js或者template.js中的错误。

这种有意的层次结构使同级路由(如导航)之间共享的重要 UI 在发生错误时保持可见和可用。

要处理layout或者template中的错误,需要在父 segment 级别放置 error.js 文件。

要处理根 layout 或者根 template 下的 error,需要使用global-error.js,它相当于error.js的变种。

捕捉 Root Layouts 的错误

app/error.js不能捕捉到app/layout.js或者app/template.js引发的错误。

要专门处理这些根组件中的错误,请使用位于根``app目录中的名为app/global-error.js的error.js`变体。

global-error.js会包裹整个应用,它的 fallback 组件会在活跃时替换掉 root layout 组件。

因此,需要注意的是,global-error.js必须定义自己的<body>和<html>标签。

global-error是颗粒最小的 error UI,可以被视为整个应用程序的“catch-all”的错误处理。它不太可能经常被触发,其他error.js 将捕获大多数错误。

即使定义了global-error.js,仍然建议定义一个 root error.js,其 fallback 组件将在root layout 中显示,其中包括全局共享的 UI。

tsx
1'use client'
2
3export default function GlobalError({ error, reset }: { error: Error; reset: () => void }) {
4  return (
5    <html>
6      <body>
7        <h2>Something went wrong!</h2>
8        <button onClick={() => reset()}>Try again</button>
9      </body>
10    </html>
11  )
12}

捕捉服务端错误

如果服务端组件抛出一个错误,Nextjs 将会指向一个 Error 对象,作为 error props 转发到最近的 error.js 文件。

保护敏感信息

在 production 环境,Error对象发送到客户端仅仅会包含一般的message和digest属性。

这是一种安全预防措施,可避免将错误中包含的潜在敏感细节泄露给客户端。

message 属性包含有关错误的通用消息,digest 属性包含可用于匹配服务器端日志中相应错误的自动生成的错误哈希值。

在development期间,Error 对象发送到客户端的信息会被序列化,并包含原始的错误信息以方便调试。