Learn Nuxt with a Collection of 100+ Tips!

错误处理

学习如何在 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.emitRouteChunkError 设置为 false(完全禁用与这些错误的连接)或 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 及其用法的更多信息。

对于自定义错误,我们强烈建议使用 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 签名
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> 组件,允许你处理应用程序内的客户端错误,而不需要用错误页面替换整个站点。

此组件负责处理其默认 slot 中发生的错误。在客户端上,它将阻止错误冒泡到顶层,并替代渲染 #error slot。

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

如果你导航到另一个路由,错误将自动被清除。
pages/index.vue
<template>
  <!-- 一些内容 -->
  <NuxtErrorBoundary @error="someErrorLogger">
    <!-- 你可以使用默认 slot 渲染内容 -->
    <template #error="{ error, clearError }">
      你可以在此处本地显示错误:{{ error }}
      <button @click="clearError">
        这将清除错误。
      </button>
    </template>
  </NuxtErrorBoundary>
</template>
Read and edit a live example in Docs > Examples > Advanced > Error Handling.