跳到主要内容

错误处理

error.js 文件约定允许您在 嵌套路由 中优雅地处理意外的运行时错误。

  • 自动将路由段及其嵌套子项包装在 React 错误边界中。
  • 使用文件系统层次结构调整细粒度,为特定段定制错误 UI。
  • 将错误隔离到受影响的段,同时保持应用程序的其余部分正常运作。
  • 添加尝试从错误中恢复而无需完全重新加载页面的功能。

通过在路由段内部添加 error.js 文件并导出一个 React 组件来创建错误 UI:

error special file

app/dashboard/error.tsx

import { useEffect } from 'react';

export default function Error({
error,
reset,
}: {
error: Error & { digest?: string };
reset: () => void;
}) {
useEffect(() => {
// 将错误记录到错误报告服务
console.error(error);
}, [error]);

return (
<div>
<h2>出了点问题!</h2>
<button
onClick={() =>
// 尝试通过尝试重新渲染段来恢复
reset()
}
>
重试
</button>
</div>
);
}

error.js 的工作原理

  • error.js 自动创建一个 React 错误边界, 包装一个嵌套的子段或 page.js 组件。
  • error.js 文件导出的 React 组件用作回退组件。
  • 如果在错误边界内引发错误,则错误被包含,将渲染回退组件。
  • 当回退错误组件处于活动状态时,位于错误边界上方的布局保持其状态并保持交互性,错误组件可以显示从错误中恢复的功能。

从错误中恢复

错误的原因有时可能是临时的。在这些情况下,简单地重试可能会解决问题。

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

app/dashboard/error.tsx
'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。
  • 错误边界不会处理在同一段中的 layout.js 组件中引发的错误,因为错误边界嵌套在该布局的组件内部。

处理布局中的错误

error.js 边界不会捕获在同一段的 layout.jstemplate.js 组件中引发的错误。 这种有意的层次结构保持了在发生错误时共享的重要 UI(如导航)可见且可交互。

要处理特定布局或模板中的错误,请在布局的父段中放置一个 error.js 文件。

要在根布局或模板中处理错误,请使用名为 global-error.jserror.js 变体。

处理根布局中的错误

app/error.js 边界不会捕获在根 app/layout.jsapp/template.js 组件中引发的错误。

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

与根 error.js 不同,global-error.js 错误边界包装整个应用程序,并在活动时用其回退组件替换根布局。 因此,请注意,global-error.js 必须定义自己的 <html><body> 标签。

global-error.js 是最不粒度的错误 UI,可以被视为整个应用程序的“全能处理”错误处理。 由于根组件通常不太动态,而其他 error.js边界将捕获大多数错误,因此很少触发。

即使定义了 global-error.js,仍建议定义一个根 error.js,其回退组件将在根布局中呈现,其中包括全局共享的 UI 和品牌。

app/global-error.tsx
'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>
)
}

处理服务器错误

如果在 Server Component 内引发错误,Next.js 将将 Error 对象(在生产中剥离了敏感错误信息的对象) 转发到最近的 error.js 文件,作为 error 属性。

保护敏感错误信息

在生产中,转发到客户端的 Error 对象仅包含一个关于错误的通用message和一个名为 digest 的属性。

这是为了防止将错误中包含的潜在敏感细节泄漏给客户端的安全预防措施。

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

在开发期间,转发到客户端的 Error 对象将被序列化,并包含原始错误的message,以便更轻松地进行调试。