错误处理

了解如何在 Nuxt 中捕获和处理错误。

Nuxt 是一个全栈框架,这意味着在不同的上下文中可能会出现几种不可避免的用户运行时错误来源:

  • Vue 渲染生命周期中的错误 (SSR & CSR)
  • 服务端和客户端启动错误 (SSR + CSR)
  • Nitro 服务端生命周期中的错误(server/ 目录)
  • 下载 JS 分块时的错误
SSR 代表服务端渲染(Server-Side Rendering),而 CSR 代表客户端渲染(Client-Side Rendering)

Vue 错误

你可以使用 onErrorCaptured 来捕获 Vue 错误。

此外,Nuxt 还提供了一个 vue:error 钩子,当有任何错误向上传播到顶层时,该钩子会被调用。

如果你正在使用错误报告框架,可以通过 vueApp.config.errorHandler 提供一个全局处理器。它将接收所有 Vue 错误,即使这些错误已经被处理。

plugins/error-handler.ts
export default defineNuxtPlugin((nuxtApp) => {
  nuxtApp.vueApp.config.errorHandler = (error, instance, info) => {
    // handle error, e.g. report to a service
  }

  // Also possible
  nuxtApp.hook('vue:error', (error, instance, info) => {
    // handle error, e.g. report to a service
  })
})
请注意,vue:error 钩子是基于 onErrorCaptured 生命周期钩子的。

启动错误

如果在启动 Nuxt 应用时出现任何错误,Nuxt 将调用 app:error 钩子。

这包括:

  • 运行 Nuxt 插件
  • 处理 app:createdapp:beforeMount 钩子
  • 将你的 Vue 应用渲染为 HTML(在 SSR 期间)
  • 挂载应用(在客户端上),尽管你应该使用 onErrorCapturedvue:error 来处理这种情况
  • 处理 app:mounted 钩子

Nitro 服务端错误

目前你无法为这些错误定义服务端处理器,但可以渲染错误页面,请参阅渲染错误页面一节。

JS 分块错误

由于网络连接故障或新的部署(这会使你旧的带有哈希值的 JS 分块 URL 失效),你可能会遇到分块加载错误。Nuxt 提供了内置支持,当在路由导航期间分块加载失败时,通过执行硬刷新(hard reload)来处理分块加载错误。

你可以通过将 experimental.emitRouteChunkError 设置为 false(以完全禁用对这些错误的挂钩)或设置为 manual(如果你想自己处理它们)来更改此行为。如果你想手动处理分块加载错误,可以查看自动实现以获取灵感。

错误页面

当 Nuxt 遇到致命错误(服务端上的任何未处理错误,或客户端上通过 fatal: true 创建的错误)时,它要么渲染一个 JSON 响应(如果使用 Accept: application/json 请求头请求),要么触发一个全屏错误页面。

在服务端生命周期中,错误可能发生于:

  • 处理你的 Nuxt 插件时
  • 将你的 Vue 应用渲染为 HTML 时
  • 服务端 API 路由抛出错误时

它也可能发生于客户端的以下情况:

  • 处理你的 Nuxt 插件时
  • 挂载应用之前(app:beforeMount 钩子)
  • 如果错误未通过 onErrorCapturedvue:error 钩子处理,则在挂载你的应用时
  • Vue 应用在浏览器中初始化并挂载(app:mounted)。
了解所有 Nuxt 生命周期钩子。

通过在应用源码目录中添加与 app.vue 并列的 ~/error.vue 来自定义默认错误页面。

error.vue
<script setup lang="ts">
import type { NuxtError } from '#app'

const props = defineProps({
  error: Object as () => NuxtError,
})

const handleError = () => clearError({ redirect: '/' })
</script>

<template>
  <div>
    <h2>{{ error?.status }}</h2>
    <button @click="handleError">
      Clear errors
    </button>
  </div>
</template>
阅读更多关于 error.vue 及其用法的信息。

对于自定义错误,我们强烈建议使用可在页面/组件 setup 函数中调用的 onErrorCaptured 组合式函数,或可在 nuxt 插件中配置的 vue:error 运行时 nuxt 钩子。

plugins/error-handler.ts
export default defineNuxtPlugin((nuxtApp) => {
  nuxtApp.hook('vue:error', (err) => {
    //
  })
})

当你准备好移除错误页面时,可以调用 clearError 辅助函数,它接受一个可选的重定向路径参数(例如,如果你想导航到一个“安全”的页面)。

在使用任何依赖于 Nuxt 插件的内容(例如 $routeuseRouter)之前,请务必进行检查,因为如果某个插件抛出了错误,在清除错误之前它不会重新运行。
渲染错误页面是一个完全独立的页面加载过程,这意味着任何注册过的中间件都会再次运行。你可以在中间件中使用 useError 来检查是否正在处理错误。
如果你正在运行 Node 16 并且在渲染错误页面时设置了任何 Cookie,它们将覆盖先前设置的 Cookie。我们建议使用较新版本的 Node,因为 Node 16 已于 2023 年 9 月到达生命周期终点(EOL)。

错误工具函数

useError

TS 签名
function useError (): Ref<Error | { url, status, statusText, message, description, data }>

此函数将返回当前正在处理的全局 Nuxt 错误。

阅读更多关于 useError 组合式函数的信息。

createError

TS 签名
function createError (err: string | { cause, data, message, name, stack, status, statusText, fatal }): Error

创建一个带有附加元数据的错误对象。你可以传递一个字符串来将其设置为错误 message,或者传递一个包含错误属性的对象。它可在应用的 Vue 部分和服务端部分使用,并且通常用于抛出(throw)。

如果你抛出一个用 createError 创建的错误:

  • 在服务端上,它会触发一个全屏错误页面,你可以使用 clearError 清除它。
  • 在客户端上,它将抛出一个非致命错误供你处理。如果你需要触发全屏错误页面,可以通过设置 fatal: true 来实现。
pages/movies/[slug].vue
<script setup lang="ts">
const route = useRoute()
const { data } = await useFetch(`/api/movies/${route.params.slug}`)

if (!data.value) {
  throw createError({
    status: 404,
    statusText: 'Page Not Found',
  })
}
</script>
statusText 属性用于简短的、符合 HTTP 标准的状态文本(例如,“Not Found”)。它只能包含水平制表符、空格和可见的 ASCII 字符([\t\u0020-\u007E])。对于任何详细描述、多行消息或包含非 ASCII 字符的内容,你应该始终改用 message 属性。
阅读更多关于 createError 工具函数的信息。

showError

TS 签名
function showError (err: string | Error | { status, statusText }): Error

你可以在客户端的任何地方调用此函数,或者(在服务端上)直接在中间件、插件或 setup() 函数中调用。它将触发一个全屏错误页面,你可以使用 clearError 将其清除。

建议改为使用 throw createError()

阅读更多关于 showError 工具函数的信息。

clearError

TS 签名
function clearError (options?: { redirect?: string }): Promise<void>

此函数将清除当前正在处理的 Nuxt 错误。它还接受一个可选的重定向路径(例如,如果你想导航到一个“安全”的页面)。

阅读更多关于 clearError 工具函数的信息。

在组件中渲染错误

Nuxt 还提供了一个 <NuxtErrorBoundary> 组件,允许你在应用内处理客户端错误,而无需用错误页面替换整个站点。

该组件负责处理在其默认插槽内发生的错误。在客户端上,它将阻止错误冒泡到顶层,并改为渲染 #error 插槽。

#error 插槽将接收 error 作为 prop。(如果将 error = null,它将触发重新渲染默认插槽;你需要确保错误首先完全解决,否则错误插槽将被再次渲染。)

如果你导航到另一个路由,错误将被自动清除。
app/pages/index.vue
<template>
  <!-- some content -->
  <NuxtErrorBoundary @error="someErrorLogger">
    <!-- You use the default slot to render your content -->
    <template #error="{ error, clearError }">
      You can display the error locally here: {{ error }}
      <button @click="clearError">
        This will clear the error.
      </button>
    </template>
  </NuxtErrorBoundary>
</template>
文档 > 4 X > 示例 > 高级 > 错误处理 中阅读并编辑在线示例。