错误处理

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

Nuxt 是一个全栈框架,这意味着在不同环境中可能会发生多种不可避免的用户运行时错误:

  • Vue 渲染生命周期中的错误(SSR & CSR)
  • 服务器和客户端启动错误(SSR + CSR)
  • Nitro 服务器生命周期中的错误(server/ 目录)
  • 下载 JS 分块时的错误
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 分块错误

你可能会遇到分块加载错误,原因可能是网络连接中断或新部署导致旧的带哈希的 JS 分块 URL 无效。Nuxt 内置支持处理分块加载错误,在路由导航时分块加载失败会执行强制刷新。

你可以通过设置 experimental.emitRouteChunkErrorfalse 来禁用这类错误钩子,或设置为 manual 以自行处理它们。如果你想手动处理分块加载错误,可以查看 自动实现 来获取灵感。

错误页面

当 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 及其用途。

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

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 Signature
function useError (): Ref<Error | { url, statusCode, statusMessage, message, description, data }>

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

阅读更多关于 useError 组合函数。

createError

TS Signature
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 Signature
function showError (err: string | Error | { statusCode, statusMessage }): Error

你可以在客户端的任何时刻调用此函数,或在服务器端的中间件、插件或 setup() 函数中直接调用。它会触发全屏错误页面,你可以通过 clearError 清除。

推荐使用 throw createError() 代替。

阅读更多关于 showError 工具。

clearError

TS Signature
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>
Read and edit a live example in Docs > Examples > Advanced > Error Handling.