错误创建与抛出
Nuxt 提供了 createError 和 showError 两个核心函数来创建和显示错误。理解它们的区别和使用场景,是正确处理应用错误的关键。
createError vs showError
| 特性 | createError | showError |
|---|---|---|
| 返回值 | 错误对象(H3Error) | undefined |
| 显示错误页面 | ❌ 不自动显示 | ✅ 立即显示 error.vue |
| 使用方式 | throw createError(...) | showError(...) |
| 适用场景 | 服务端 API、中间件 | 客户端组件、路由中间件 |
| 典型位置 | server/api/ | app/ 客户端代码 |
核心区别
createError:创建错误对象,需要throw才能触发showError:创建并显示错误,直接触发error.vue
简单记忆
服务端用 throw createError(),客户端用 showError()。
createError
创建错误对象,可以在服务端和客户端使用:
服务端使用
ts
// server/api/users/[id].ts
export default defineEventHandler((event) => {
const id = getRouterParam(event, 'id')
// 参数校验失败
if (!id || !/^\d+$/.test(id)) {
throw createError({
statusCode: 400,
statusMessage: 'Bad Request',
message: 'ID 必须是数字',
})
}
const user = findUser(Number(id))
// 资源不存在
if (!user) {
throw createError({
statusCode: 404,
statusMessage: 'Not Found',
message: '用户不存在',
})
}
// 无权限
if (!canView(event.context.user, user)) {
throw createError({
statusCode: 403,
statusMessage: 'Forbidden',
message: '无权查看此用户',
})
}
return user
})服务端 throw createError() 的行为
- 创建 H3Error 对象
- H3 捕获错误,返回对应状态码的 HTTP 响应
- 客户端
useFetch收到错误响应,设置errorref - 不会自动显示错误页面——客户端需要自己处理
客户端使用
ts
// 在组件中创建错误(不常用,推荐用 showError)
const error = createError({
statusCode: 404,
statusMessage: 'Not Found',
message: '页面不存在',
})
// 需要手动 throw 才能触发
// throw error错误选项
ts
createError({
statusCode: 400, // HTTP 状态码(必填)
statusMessage: 'Bad Request', // 状态消息(简短的 HTTP 状态描述,会被 HTTP 响应使用)
message: '邮箱格式不正确', // 详细错误信息(面向用户的描述,可包含中文等长文本)
fatal: false, // 是否致命错误(致命错误无法通过 clearError 恢复)
data: { field: 'email' }, // 附加数据(可传递额外错误信息)
})INFO
️ statusMessage vs message 的区别
statusMessage:简短的 HTTP 状态描述(如"Bad Request"、"Not Found"),会被 H3 用于 HTTP 响应状态行,未来版本将默认进行 sanitize(过滤非 ASCII 字符和特殊字符),不要在此放中文或长文本message:详细的错误描述(如"用户不存在"、"邮箱格式不正确"),可包含中文等任意文本,适合传递给前端展示
如果你将中文或长文本放在 statusMessage 中,会收到 h3 的警告:
text
WARN [h3] Please prefer using message for longer error messages instead of statusMessage.
In the future, statusMessage will be sanitized by default.最佳实践
statusMessage 使用标准 HTTP 状态文本(英文短描述),message 使用面向用户的详细描述(可以是中文)。
简写形式
ts
// 直接传字符串(默认 500 状态码)
throw createError('出错了')
// 传状态码
throw createError({ statusCode: 404 })INFO
️ fatal: true 的含义:致命错误会完全替换当前页面状态 clearError 无法恢复。只在应用完全不可用时使用(如全局状态损坏)
showError
在客户端主动显示全屏错误页面:
在组件中使用
ts
const handleDangerousAction = () => {
showError({
statusCode: 403,
statusMessage: 'Forbidden',
message: '无权执行此操作',
})
}在路由中间件中使用
ts
export default defineNuxtRouteMiddleware((to) => {
if (!isAuthorized()) {
return showError({
statusCode: 403,
statusMessage: 'Forbidden',
message: '需要管理员权限',
})
}
})showError 的行为
- 创建错误对象
- 立即显示
error.vue - 当前页面被替换
- 用户可以通过
clearError恢复
完整流程——服务端 + 客户端配合
ts
// 服务端:抛出错误
// server/api/admin/users.ts
export default defineEventHandler((event) => {
if (!event.context.user?.isAdmin) {
throw createError({ statusCode: 403, statusMessage: 'Forbidden', message: '需要管理员权限' })
}
return getAllUsers()
})
// 客户端:useFetch 自动处理错误
const { data, error } = await useFetch('/api/admin/users')
// 如果需要主动显示错误页面
if (error.value && error.value.statusCode === 403) {
showError(error.value)
}常见 HTTP 错误码
| 状态码 | 说明 | 典型场景 | 是否应该 showError |
|---|---|---|---|
| 400 | Bad Request | 参数校验失败 | ❌ 表单内提示 |
| 401 | Unauthorized | 未登录 | ❌ 跳转登录页 |
| 403 | Forbidden | 无权限 | ✅ 显示错误页面 |
| 404 | Not Found | 资源不存在 | ✅ 显示 404 页面 |
| 409 | Conflict | 数据冲突 | ❌ 表单内提示 |
| 422 | Unprocessable Entity | 请求体格式错误 | ❌ 表单内提示 |
| 429 | Too Many Requests | 请求频率过高 | ❌ 提示稍后重试 |
| 500 | Internal Server Error | 服务器内部错误 | ✅ 显示错误页面 |
哪些错误应该用 showError 显示全屏错误页面?
- 403:用户明确无权访问,需要全局提示
- 404:页面/资源不存在,需要全局提示
- 500:服务端错误,需要全局提示
❌ 不应该用 showError 的场景:
- 400/422:表单验证错误,应该在表单内显示
- 401:应该跳转到登录页
- 409:数据冲突,应该在表单内显示
- 429:频率限制,用 toast 提示
$fetch 错误处理
$fetch 在 4xx/5xx 状态码时会抛出 FetchError,需要 try/catch 处理:
ts
try {
const data = await $fetch('/api/users')
} catch (error) {
if (error instanceof FetchError) {
switch (error.statusCode) {
case 401:
navigateTo('/login')
break
case 403:
showError({ statusCode: 403, statusMessage: 'Forbidden', message: '无权限' })
break
case 404:
showError({ statusCode: 404, statusMessage: 'Not Found', message: '未找到' })
break
default:
showError({ statusCode: 500, statusMessage: 'Internal Server Error', message: '服务器错误' })
}
}
}$fetch vs useFetch 的错误处理
$fetch:抛出异常,需要try/catchuseFetch:返回errorref,不需要try/catch
页面级数据加载用 useFetch
(自动处理错误),事件处理中用 $fetch(手动处理错误)。
知识脉络
text
错误页面 → 你在这里:错误创建与抛出
│
├─→ 下一步:错误清除
│
└─→ 相关:服务端开发 → 事件处理(createError 在服务端的使用)