Skip to content

错误创建与抛出

Nuxt 提供了 createErrorshowError 两个核心函数来创建和显示错误。理解它们的区别和使用场景,是正确处理应用错误的关键。

createError vs showError

特性createErrorshowError
返回值错误对象(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() 的行为

  1. 创建 H3Error 对象
  2. H3 捕获错误,返回对应状态码的 HTTP 响应
  3. 客户端 useFetch 收到错误响应,设置 error ref
  4. 不会自动显示错误页面——客户端需要自己处理

客户端使用

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 的行为

  1. 创建错误对象
  2. 立即显示 error.vue
  3. 当前页面被替换
  4. 用户可以通过 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
400Bad Request参数校验失败❌ 表单内提示
401Unauthorized未登录❌ 跳转登录页
403Forbidden无权限✅ 显示错误页面
404Not Found资源不存在✅ 显示 404 页面
409Conflict数据冲突❌ 表单内提示
422Unprocessable Entity请求体格式错误❌ 表单内提示
429Too Many Requests请求频率过高❌ 提示稍后重试
500Internal 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/catch
  • useFetch:返回 error ref,不需要 try/catch

页面级数据加载用 useFetch

(自动处理错误),事件处理中用 $fetch(手动处理错误)。

知识脉络

text
错误页面 → 你在这里:错误创建与抛出

            ├─→ 下一步:错误清除

            └─→ 相关:服务端开发 → 事件处理(createError 在服务端的使用)

基于 Nuxt 4 官方文档整理编写