错误处理
Nuxt 是全栈框架,错误可能来自四个方向:Vue 渲染、应用启动、Nitro 服务端、JS chunk 下载。每一种都有对应的处理工具。
Vue 错误
在组件内用 onErrorCaptured 捕获;全局一次性注册用插件:
// app/plugins/error-report.ts
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.vueApp.config.errorHandler = (error, instance, info) => {
// 上报到 Sentry / Datadog / 自己的后端
}
nuxtApp.hook('vue:error', (error, instance, info) => {
// 即使被处理过的错误也会触发
})
})
vue:error 就是 Nuxt 版的 onErrorCaptured —— 所有冒泡到顶层的错误都会过这里。
启动错误
插件初始化、SSR、客户端挂载阶段的错误会触发 app:error。可在这里做埋点、清缓存、重置状态。
Nitro 服务端错误
服务端错误不会被 Vue 边界捕获,会直接进入错误页面。要自定义响应,在 event handler 里 throw createError({...}):
// server/api/posts/[id].get.ts
export default defineEventHandler((event) => {
const post = findPost(event.context.params!.id)
if (!post) {
throw createError({ status: 404, statusText: 'Post not found' })
}
return post
})
Chunk 加载失败
用户停留在旧页面、你又重新部署时,旧的 chunk URL 可能 404。Nuxt 默认会触发硬刷新。想自定义,把 experimental.emitRouteChunkError 设为 'manual',然后自己监听 nuxt:chunk-error。
error.vue —— 兜底页面
触发致命错误(未捕获的服务端错误、或客户端 createError({ fatal: true }))时,Nuxt 会渲染 ~/error.vue:
<!-- error.vue -->
<script setup lang="ts">
import type { NuxtError } from '#app'
const props = defineProps<{ error: NuxtError }>()
const handleError = () => clearError({ redirect: '/' })
</script>
<template>
<section>
<h1>{{ error.statusCode }}</h1>
<p>{{ error.statusMessage }}</p>
<button @click="handleError">回首页</button>
</section>
</template>
几个细节:
error.vue是一次单独的页面渲染,路由中间件会重新跑。可以用useError()判断“当前是不是错误页”。Accept: application/json的请求不会拿到 HTML,而是 JSON 响应。
抛错:createError
import { createError } from '#app'
if (!data.value) {
throw createError({
status: 404,
statusText: 'Page Not Found',
})
}
- 在服务端(setup / 插件 / handler)抛出,会直接进错误页面。
- 在客户端默认是非致命的;要进错误页,加
{ fatal: true }。
statusText 请保持简短、仅 ASCII。长描述或国际化文案放到 message 或 data 里。
showError 与 clearError
showError(err):命令式触发错误页面。clearError({ redirect: '/' }):清掉当前错误,可选跳转。
setup / handler 里优先 throw createError(...);已经 catch 住再手动暴露时再用 showError。
NuxtErrorBoundary —— 局部错误 UI
不要因为一个组件挂了就崩整页,包一层:
<template>
<NuxtErrorBoundary @error="report">
<RemoteChart />
<template #error="{ error, clearError }">
<p>图表加载失败。</p>
<button @click="clearError">重试</button>
</template>
</NuxtErrorBoundary>
</template>
<script setup lang="ts">
function report (err: unknown) { /* 上报 */ }
</script>
error = null 会重新渲染默认 slot,所以要先解决根因,否则 slot 立刻再抛。
useError() —— 读取当前错误
在中间件、插件、布局里都能读:
const error = useError()
if (error.value) {
// 正处于错误页流程
}
用来跳过登录检查、隐藏外壳都很方便。
Checklist
- 插件里注册全局 handler(
errorHandler+vue:error)。 - 提供
error.vue,给用户一条友好的恢复路径。 - Nitro handler 用
createError抛 4xx / 5xx。 - 高风险组件包
NuxtErrorBoundary。 - 上报 chunk-error 指标,及时发现发版导致的会话中断。
好的错误体验本身就是一个功能,认真对待。