错误处理
Nuxt 3 是一个全栈框架,这意味着在不同的上下文中可能会发生几种无法预防的用户运行时错误:
- Vue 渲染生命周期中的错误(SSR 和 CSR)
- Nitro 服务器生命周期中的错误(
server/
目录) - 服务器和客户端启动错误(SSR + CSR)
- 下载 JS chunk 时出错
Vue 渲染生命周期
你可以使用 onErrorCaptured
来捕获 Vue 错误。
此外,Nuxt 还提供了一个 vue:error
钩子,如果有任何错误传播到顶层,将会调用该钩子。
如果你使用的是错误报告框架,你可以通过 vueApp.config.errorHandler
提供一个全局处理程序。它将接收所有的 Vue 错误,即使这些错误已经被处理。
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:created
和app:beforeMount
钩子 - 将你的 Vue 应用渲染为 HTML(在 SSR 期间)
- 挂载应用程序(在客户端),不过你应该使用
onErrorCaptured
或vue:error
来处理这种情况 - 处理
app:mounted
钩子
Nitro 服务器生命周期
目前你无法为这些错误定义一个服务器端处理程序,但可以渲染一个错误页面,参见 渲染错误页面 部分。
JS chunk 错误
由于网络连接故障或新部署(使旧的散列 JS chunk URL 失效),你可能会遇到块加载错误。Nuxt 提供了内置支持来处理块加载错误,当在路由导航过程中某个块加载失败时,它会执行硬刷新。
你可以通过将 experimental.emitRouteChunkError
设置为 false
(完全禁用对这些错误的处理)或 manual
(手动处理错误)来更改此行为。如果你想手动处理块加载错误,你可以查看 自动实现 来获取一些想法。
错误页面
fatal: true
创建的错误),它将要么渲染一个 JSON 响应(如果使用 Accept: application/json
头部请求),要么触发一个全屏错误页面。在以下情况下,可能会在服务器生命周期中发生错误:
- 处理 Nuxt 插件
- 将你的 Vue 应用程序渲染为 HTML
- 服务器 API 路由抛出错误
它也可能在客户端上发生以下情况:
- 处理 Nuxt 插件
- 在挂载应用程序之前(
app:beforeMount
钩子) - 如果错误没有使用
onErrorCaptured
或vue:error
钩子进行处理,则在挂载应用程序时 - 在浏览器中初始化和挂载 Vue 应用程序(
app:mounted
)。
通过在应用程序源目录中添加 ~/error.vue
,可以自定义默认错误页面,与 app.vue
放在一起。
<script setup lang="ts">
const props = defineProps({
error: Object
})
const handleError = () => clearError({ redirect: '/' })
</script>
<template>
<div>
<h2>{{ error.statusCode }}</h2>
<button @click="handleError">清除错误</button>
</div>
</template>
~/pages
目录中。出于同样的原因,你不应该在此页面中使用 definePageMeta
。错误页面有一个单一的 prop - error
,其中包含一个待处理的错误。
error
对象提供以下字段:
{
url: string
statusCode: number
statusMessage: string
message: string
description: string
data: any
}
如果你有一个带有自定义字段的错误,它们将会丢失;你应该将它们分配给 data
:
throw createError({
statusCode: 404,
statusMessage: 'Page Not Found',
data: {
myCustomField: true
}
})
对于自定义错误,我们强烈建议使用 onErrorCaptured
组合式,它可以在页面/组件设置函数中调用,或者使用 vue:error
运行时的 Nuxt 钩子,可以在 Nuxt 插件中进行配置。
export default defineNuxtPlugin(nuxtApp => {
nuxtApp.hook('vue:error', (err) => {
//
})
})
当你准备移除错误页面时,你可以调用 clearError
辅助函数,它接受一个可选的路径进行重定向(例如,如果你想导航到一个“安全”的页面)。
$route
或 useRouter
,因为如果插件抛出错误,那么插件将不会重新运行,直到你清除错误为止。错误工具
useError
function useError (): Ref<Error | { url, statusCode, statusMessage, message, description, data }>
此函数将返回正在处理的全局 Nuxt 错误。
createError
function createError (err: { cause, data, message, name, stack, statusCode, statusMessage, fatal }): Error
使用附加元数据创建错误对象。它可以在你的应用程序的 Vue 和服务器部分中使用,并且意在被抛出。
如果你抛出使用 createError
创建的错误:
- 在服务器端,它将触发一个全屏错误页面,你可以使用
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
你可以在客户端的任何地方调用此函数,或者(在服务器端)直接在中间件、插件或 setup()
函数中使用。它将触发一个全屏错误页面,你可以使用 clearError
清除该错误。
建议使用 throw createError()
。
clearError
function clearError (options?: { redirect?: string }): Promise<void>
此函数将清除当前正在处理的 Nuxt 错误。它还接受一个可选的路径进行重定向(例如,如果你想导航到一个“安全”的页面)。
在组件中渲染错误
Nuxt 还提供了一个 <NuxtErrorBoundary>
组件,允许你在应用程序中处理客户端错误,而无需用错误页面替换整个站点。
该组件负责处理其默认插槽中发生的错误。在客户端上,它将阻止错误冒泡到顶层,并渲染 #error
插槽。
#error
插槽将接收 error
作为 prop。(如果你设置 error = null
,它将触发重新渲染默认插槽;你需要确保错误已经完全解决,否则错误插槽将被再次渲染。)
<template>
<!-- 一些内容 -->
<NuxtErrorBoundary @error="someErrorLogger">
<!-- 使用默认插槽来渲染你的内容 -->
<template #error="{ error, clearError }">
你可以在此处局部显示错误:{{ error }}
<button @click="clearError">
这将清除错误。
</button>
</template>
</NuxtErrorBoundary>
</template>