Nuxt4 错误处理
网站总会出错,404 页面不存在、500 服务器异常、接口请求失败。好的错误处理让用户看到友好的提示,而不是一片空白或难看的报错页。
全局错误页面
在 app/error.vue 创建全局错误页面,任何未处理的错误都会渲染到这里:
<!-- app/error.vue -->
<script setup>
// useError 拿到当前错误信息
const error = useError()
function handleBack() {
clearError({ redirect: '/' }) // 清除错误并跳回首页
}
</script>
<template>
<div class="error-page">
<h1>{{ error?.statusCode || '出错了' }}</h1>
<p>{{ error?.statusMessage || error?.message }}</p>
<button @click="handleBack">返回首页</button>
</div>
</template>
访问一个不存在的地址,比如 /nonexistent-page,就会看到这个页面显示 404 错误。
注意:error.vue 在 Nuxt 4 中位于 app/error.vue,与 app.vue 平级,它有自己的渲染环境,不经过布局。
主动抛出错误
在接口中抛出
接口层用 createError 抛错,客户端会收到对应状态码:
// server/api/users/[id].get.ts
export default defineEventHandler((event) => {
const id = getRouterParam(event, 'id')
if (id === '999') {
throw createError({
statusCode: 404,
statusMessage: '用户不存在'
})
}
return { id }
})
在页面中抛出
<!-- app/pages/posts/[id].vue -->
<script setup>
const route = useRoute()
const { data: post } = await useFetch(`/api/posts/${route.params.id}`)
// 数据为空时抛出 404 错误,渲染到全局错误页
if (!post.value) {
throw createError({
statusCode: 404,
statusMessage: '文章不存在'
})
}
</script>
数据请求失败的处理
接口失败时不一定跳错误页,可以在页面内优雅处理,配合数据获取篇的 error:
<script setup>
const { data, error, refresh } = await useFetch('/api/users')
</script>
<template>
<div v-if="error">
<p>加载失败:{{ error.statusMessage }}</p>
<button @click="refresh">重试</button>
</div>
<ul v-else>
<li v-for="user in data" :key="user.id">{{ user.name }}</li>
</ul>
</template>
提示:请求接口失败默认不会跳转全局错误页(除非设置了 throw: true),页面内的 error 状态更适合局部处理。
组件级错误边界
<NuxtErrorBoundary> 可以捕获组件内部的渲染错误,只影响局部区域,不影响整页:
<template>
<div>
<h1>文章列表</h1>
<NuxtErrorBoundary>
<PostList />
<!-- 子组件出错时显示这个插槽 -->
<template #error="{ error }">
<p>列表加载失败</p>
<button @click="error.value = null">重试</button>
</template>
</NuxtErrorBoundary>
</div>
</template>
适合隔离单个功能模块的错误,比如侧边栏挂了不影响主内容区。
错误处理速查表
| 场景 | 做法 |
|---|---|
| 全局错误页 | 创建 app/error.vue,用 useError() 读取错误 |
| 清除错误跳转 | clearError({ redirect: '/' }) |
| 接口抛错 | throw createError({ statusCode, statusMessage }) |
| 页面判断数据缺失 | 数据为空时 throw createError(...) |
| 请求失败局部提示 | 用 useFetch 的 error 状态配合重试按钮 |
| 隔离组件错误 | 用 <NuxtErrorBoundary> 包住组件 |
一句话总结:app/error.vue 兜底全局错误,createError 主动抛出可控错误,useFetch 的 error 处理请求失败,NuxtErrorBoundary 隔离局部错误。