错误处理
了解如何在 Nuxt 中捕获和处理错误。
Nuxt 是一个全栈框架,这意味着有若干来源的、无法预防的用户运行时错误可能发生在不同的上下文中:
- Vue 渲染生命周期期间的错误(SSR 和 CSR)
- 服务端和客户端启动错误(SSR + CSR)
- Nitro 服务端生命周期期间的错误(
server/目录) - 下载 JS chunk 时的错误
Vue 错误(Vue Errors)
你可以使用 onErrorCaptured 来钩入 Vue 错误。
此外,Nuxt 提供了一个 vue:error 钩子,如果任何错误冒泡到顶层,它就会被调用。
如果你在使用错误报告框架,可以通过 vueApp.config.errorHandler 提供一个全局处理器。它会收到所有 Vue 错误,即使它们已被处理。
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
})
})
vue:error 钩子基于 onErrorCaptured 生命周期钩子。启动错误(Startup Errors)
如果在启动 Nuxt 应用时出现任何错误,Nuxt 会调用 app:error 钩子。
这包括:
- 运行 Nuxt 插件
- 处理
app:created和app:beforeMount钩子 - 将你的 Vue 应用渲染为 HTML(在 SSR 期间)
- 挂载应用(在客户端),不过你应该用
onErrorCaptured或vue:error来处理这种情况 - 处理
app:mounted钩子
Nitro 服务端错误(Nitro Server Errors)
目前你无法为这些错误定义服务端处理器,但可以渲染一个错误页面,见渲染错误页面小节。
JS Chunk 错误(Errors with JS Chunks)
你可能会由于网络连接失败或一次新的部署(会使旧的、带哈希的 JS chunk URL 失效)而遇到 chunk 加载错误。Nuxt 内置了对 chunk 加载错误的处理支持:当在路由导航期间某个 chunk 加载失败时,会执行一次硬刷新(hard reload)。
你可以通过设置 experimental.emitRouteChunkError 为 false(完全禁用对这些错误的钩入)或 manual(如果你想自己处理)来改变这种行为。如果你想手动处理 chunk 加载错误,可以查看自动实现 获取思路。
错误页面(Error Page)
fatal: true 创建的错误)时,它会渲染一个 JSON 响应(如果请求带有 Accept: application/json 请求头),或者触发一个全屏错误页面。在服务端生命周期中,错误可能在以下情况发生:
- 处理你的 Nuxt 插件
- 将你的 Vue 应用渲染为 HTML
- 服务端 API 路由抛出错误
它也可能在客户端发生,当:
- 处理你的 Nuxt 插件
- 在挂载应用之前(
app:beforeMount钩子) - 挂载你的应用,如果错误未被
onErrorCaptured或vue:error钩子处理 - Vue 应用在浏览器中被初始化并挂载(
app:mounted)。
发现所有 Nuxt 生命周期钩子。 :::
通过在应用程序的源代码目录中(与 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?.status }}</h2>
<button @click="handleError">
Clear errors
</button>
</div>
</template>
阅读更多关于 error.vue 及其用途的内容。
:::
对于自定义错误,我们强烈推荐使用 onErrorCaptured composable(可以在页面/组件 setup 函数中调用)或 vue:error 运行时 nuxt 钩子(可以在 nuxt 插件中配置)。
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.hook('vue:error', (err) => {
//
})
})
当你准备移除错误页面时,可以调用 clearError 辅助函数,它接受一个可选的路径用于重定向(例如,如果你想导航到一个“安全”页面)。
在使用任何依赖 Nuxt 插件的内容(如 $route 或 useRouter)之前,请确保检查,因为如果某个插件抛出了错误,那么在清除错误之前它不会重新运行。
useError 来检查是否正在处理一个错误。错误工具(Error Utils)
useError
function useError (): Ref<Error | { url, status, statusText, message, description, data }>
这个函数会返回正在被处理的全局 Nuxt 错误。
阅读更多关于 useError composable 的内容。
:::
createError
function createError (err: string | { cause, data, message, name, stack, status, statusText, fatal }): Error
创建一个带有额外元数据的错误对象。你可以传入一个字符串,作为错误的 message,或者传入一个包含错误属性的对象。它可以在你应用的 Vue 部分和服务端部分中使用,并且应当被抛出。
如果你抛出一个用 createError 创建的错误:
- 在服务端,它会触发一个全屏错误页面,你可以用
clearError来清除它。 - 在客户端,它会抛出一个非致命错误供你处理。如果你需要触发全屏错误页面,则可以通过将
fatal: true来实现。
在开发环境下,错误的 cause 会被保留并暴露给你的错误页面,以便你追溯原始错误;在生产环境下,cause 永远不会包含在错误响应或错误页面 payload 中。
<script setup lang="ts">
const route = useRoute()
const { data } = await useFetch(`/api/movies/${route.params.slug}`)
if (!data.value) {
throw createError({
status: 404,
statusText: 'Page Not Found',
})
}
</script>
statusText 属性用于简短的、符合 HTTP 规范的状态文本(例如「Not Found」)。它只能包含水平制表符、空格和可见的 ASCII 字符([\t\u0020-\u007E])。对于任何详细描述、多行消息或包含非 ASCII 字符的内容,你应该始终使用 message 属性。阅读更多关于 createError 工具的内容。
:::
showError
function showError (err: string | Error | { status, statusText }): Error
你可以在客户端任何时刻调用此函数,或(在服务端)直接在 middleware、插件或 setup() 函数中调用。它会触发一个全屏错误页面,你可以用 clearError 清除它。
推荐改用 throw createError()。
阅读更多关于 showError 工具的内容。
:::
clearError
function clearError (options?: { redirect?: string }): Promise<void>
这个函数会清除当前正在处理的 Nuxt 错误。它还接受一个可选的路径用于重定向(例如,如果你想导航到一个“安全”页面)。
阅读更多关于 clearError 工具的内容。
:::
在组件中渲染错误(Render Error in Component)
Nuxt 还提供了 <NuxtErrorBoundary> 组件,允许你在应用内处理客户端错误,而无需用错误页面替换整个站点。
该组件负责处理其默认插槽(default slot)中发生的错误。在客户端,它会阻止错误冒泡到顶层,并转而渲染 #error 插槽。
#error 插槽会接收 error 作为 prop。(如果你设置 error = null,它会触发默认插槽的重新渲染;你需要先确保错误已被完全解决,否则错误插槽会再次被渲染。)
<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>