【Nuxt3系列十一】错误处理

508 阅读4分钟

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

  • Vue渲染生命周期中的错误(SSR & CSR)
  • 服务器和客户端启动错误(SSR + CSR)
  • Nitro服务器生命周期中的错误(server/ directory)
  • 下载js块的时候会出错

Vue Errors

你可以使用onErrorCaptured去hook Vue的错误。

此外,Nuxt还提供了一个vue:error钩子,如果任何错误传播到顶层,就会调用它

如果你用了一些错误报告框架,你可以通过vueApp.config.errorHandler提供一个全局处理程序。即便错误都被处理了。

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
  })
})

启动错误

Nuxt会使用app:error钩子函数处理任何应用启动时候的error

这包括了:

  • 运行Nuxt 插件
  • 处理app:created 和 app:beforeMount 钩子
  • 将你的 Vue 应用程序渲染成 HTML(在服务端渲染期间)
  • 在客户端挂载应用程序,尽管你应该通过 onErrorCaptured 或 vue:error 来处理这种情况
  • 处理 app:mounted 钩子

Nitro 服务器错误

目前你不能为这些错误定义服务器端的处理器,但你可以渲染一个错误页面,请参阅“渲染错误页面”部分。

js块的错误

你可能会因为网络连接问题或者新部署(这会导致旧的哈希过的 JavaScript Chunk URL 变为无效)而遇到 Chunk 加载错误。Nuxt 提供了内置支持来处理 Chunk 加载错误,即当 Chunk 在路由导航期间加载失败时执行硬刷新。 你可以通过设置 experimental.emitRouteChunkError 来改变这种行为:将其设置为 false(完全禁用对这些错误的捕获)或者 manual 如果你想自己处理这些错误。如果你想手动处理 Chunk 加载错误,可以参考自动实现的部分以获取灵感。

错误页面

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

在服务器生命周期中可能发生错误的情况包括:

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

在客户端也可能发生错误的情况包括:

  • 处理你的 Nuxt 插件
  • 在挂载应用程序之前 (app:beforeMount 钩子)
  • 挂载你的应用程序时,如果错误没有被 onErrorCaptured 或 vue:error 钩子处理
  • Vue 应用程序在浏览器中初始化并挂载 (app:mounted) 时

通过在应用根目录创建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">Clear errors</button>
  </div>
</template>

对于自定义错误,强烈推荐使用onErrorCaptured,它可以在setup中调用。或者是使用vue:error

plugins/error-handler.ts

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

当你准备取消展示错误页面,你可以调用clearError函数,并重定向到一个正确的页面

任何依赖Nuxt plugins的东西在运行的时候,如果发生了错误,他不会重新运行,直到你清除错误。例如$routeruseRouter

渲染错误页面是一个独立的页面加载,因此也是需要走各种中间件的,你可以在中间件中使用useError来检查错误是否正在被处理

Node16在渲染错误页面的时候设置了一个cookie的话,会覆盖之前设置的cookie,所以不要用node16了!

Error Utils

useError

会返回一个全局的Nuxt Error

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

createError

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

创建一个带有附加元数据的error object。你可以通过一个string去设置message或者传递一个包含错误属性的对象。它可以在vue和服务器部分中使用。

  • 如果在服务器端调用,会触发一个全屏的错误页面。可以通过clearError去掉
  • 如果在客户端,将会抛出一个非致命的错误,以便你处理。如果你想触发全屏的错误页面,你可以通过fatal:true来实现
<script setup lang="ts">
const route = useRoute()
const { data } = await useFetch(`/api/movies/${route.params.slug}`)

if (!data.value) {
  throw createError({
    statusCode: 404,
    statusMessage: 'Page Not Found'
  })
}
</script>

showError

function showError (err: string | Error | { statusCode, statusMessage }): Error

clearError

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

可以清除掉展示出来的错误页面,重定向到新的页面,允许你在应用内处理客户端错误。而无需用错误页面

组件的渲染错误

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

这个组件负责处理在其默认插槽内发生的错误。在客户端,它将阻止错误冒泡到顶级,并将渲染 #error 插槽代替。

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

<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>