错误处理
Nuxt 是一个全栈框架,这意味着在不同的上下文中可能会出现一些无法避免的用户运行时错误:
- Vue 渲染生命周期中的错误(SSR 和 CSR)
- 服务器和客户端启动错误(SSR + CSR)
- Nitro 服务器生命周期中的错误(
server/
目录) - 下载 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 失效),你可能会遇到 chunk 加载错误。Nuxt 提供了内置支持来处理 chunk 加载错误,当在路由导航期间加载 chunk 失败时,会执行硬重载。
你可以通过将 experimental.emitRouteChunkError
设置为 false
(完全禁用对这些错误的钩子)或 manual
(如果你想自己处理它们)来更改此行为。如果你想手动处理 chunk 加载错误,可以查看 自动实现 获取灵感。
错误页面
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">
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>
对于自定义错误,我们强烈建议使用 onErrorCaptured
组合式函数(可以在页面/组件的 setup 函数中调用)或 vue:error
运行时 nuxt 钩子(可以在 nuxt 插件中配置)。
export default defineNuxtPlugin(nuxtApp => {
nuxtApp.hook('vue:error', (err) => {
//
})
})
当你准备好移除错误页面时,可以调用 clearError
辅助函数,该函数接受一个可选的重定向路径(例如,如果你想导航到一个“安全”页面)。
$route
或 useRouter
,因为如果一个插件抛出错误,那么在你清除错误之前它不会重新运行。useError
来检查是否正在处理错误。错误工具
useError
function useError (): Ref<Error | { url, statusCode, statusMessage, message, description, data }>
此函数将返回正在处理的全局 Nuxt 错误。
createError
function createError (err: string | { cause, data, message, name, stack, statusCode, statusMessage, fatal }): Error
创建一个带有附加元数据的错误对象。你可以传递一个字符串作为错误的 message
,或者一个包含错误属性的对象。它可在应用的 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: '页面未找到'
})
}
</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>