错误处理

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

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

  • Vue 渲染生命周期中的错误(SSR 和 CSR)
  • 服务器和客户端启动错误(SSR + CSR)
  • Nitro 服务器生命周期中的错误(server/ 目录)
  • 下载 JS chunk 时的错误
SSR 代表 服务器端渲染CSR 代表 客户端渲染

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) => {
    // 处理错误,例如报告到某个服务
  }

  // 也可以这样
  nuxtApp.hook('vue:error', (error, instance, info) => {
    // 处理错误,例如报告到某个服务
  })
})
注意,vue:error 钩子基于 onErrorCaptured 生命周期钩子。

启动错误

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

这包括:

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

Nitro 服务器错误

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

JS chunk 错误

由于网络连接失败或新部署(这会使你的旧的、经过哈希处理的 JS chunk URL 失效),你可能会遇到 chunk 加载错误。Nuxt 提供了内置支持来处理 chunk 加载错误,当在路由导航期间加载 chunk 失败时,会执行硬重载。

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

错误页面

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

在服务器生命周期中,可能会在以下情况发生错误:

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

在客户端,也可能在以下情况发生错误:

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

通过在应用的源目录中添加 ~/error.vue(与 app.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?.statusCode }}</h2>
    <button @click="handleError">清除错误</button>
  </div>
</template>
了解更多关于 error.vue 及其用途。

对于自定义错误,我们强烈建议使用 onErrorCaptured 组合式函数(可以在页面/组件的 setup 函数中调用)或 vue:error 运行时 nuxt 钩子(可以在 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 月已达到生命周期结束。

错误工具

useError

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

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

了解更多关于 useError 组合式函数。

createError

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

创建一个带有附加元数据的错误对象。你可以传递一个字符串作为错误的 message,或者一个包含错误属性的对象。它可在应用的 Vue 部分和服务器部分使用,旨在被抛出。

如果你抛出一个用 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({
    statusCode: 404,
    statusMessage: '页面未找到'
  })
}
</script>
了解更多关于 createError 工具。

showError

TS 签名
function showError (err: string | Error | { statusCode, statusMessage }): 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,它将触发重新渲染默认插槽;你需要确保错误已完全解决,否则错误插槽将只被渲染第二次。)

如果你导航到另一个路由,错误将自动清除。
pages/index.vue
<template>
  <!-- 一些内容 -->
  <NuxtErrorBoundary @error="someErrorLogger">
    <!-- 你使用默认插槽来渲染你的内容 -->
    <template #error="{ error, clearError }">
      你可以在这里本地显示错误:{{ error }}
      <button @click="clearError">
        这将清除错误。
      </button>
    </template>
  </NuxtErrorBoundary>
</template>
阅读并编辑实时示例中的内容 Docs > Examples > Advanced > Error Handling.