首页
/ Nuxt createError 完全指南:在 Vue 页面与 Nitro API 路由中创建、抛出并传递带元数据的错误

Nuxt createError 完全指南:在 Vue 页面与 Nitro API 路由中创建、抛出并传递带元数据的错误

2026-09-07 17:07:27作者:宣利权Counsellor

createError 是 Nuxt 全栈应用中用于创建「带附加元数据的错误对象」的核心工具函数,它同时适用于 Vue(客户端与 SSR)与 Nitro 服务器两大部分,且设计的最终目的就是被 throw。本文基于 create-error 参考文档,结合 error.ts 源码 与配套测试,系统讲解其参数契约、SSR/CSR 行为差异、cause 错误链传递规则,以及在 API 路由中返回结构化错误给前端的完整实践。

createError 是什么:专为「抛出」而生的错误工厂

从类型签名来看,createError 接受一个字符串或一个错误详情对象:

function createError (err: string | Error | { cause, data, message, name, stack, status, statusText, fatal }): NuxtError

它返回一个 NuxtError 实例——该实例继承自原生 Error,同时带有 statusstatusTextdatafatal 等 HTTP/错误页所需的元数据字段。这一点与普通 new Error() 有本质区别:Nuxt 的渲染管线与 Nitro 服务器能够识别这个错误对象所携带的元数据,从而正确渲染错误页或返回对应的 HTTP 状态码。

error.ts 源码 可以看出,createError 的实现非常轻量,它其实是一个构造函数分派器

export const createError = <DataT = unknown>(error: string | Error | NuxtErrorDetails<DataT>): NuxtError<DataT> => {
  if (isNuxtError<DataT>(error)) { return error }
  return typeof error === 'string'
    ? new NuxtError<DataT>(error)
    : new NuxtError<DataT>(error.message ?? '', error as NuxtErrorDetails<DataT>)
}

其中有两个值得注意的分支行为:

  1. 幂等性:如果你传入的已经是 NuxtError(源码通过 NUXT_ERROR_SIGNATURE = '__nuxt_error' 标记与 isNuxtError 判断),它会原样返回,不会二次包装。这意味着在层层传递的错误处理代码中重复调用 createError 是安全的。error.test.tsexpect(createError(error)).toBe(error) 正是对这条行为的验证。
  2. 字符串消息默认 500:若传入的是字符串,它会被当作错误的 message,而 status 会默认落到 500(见 error.test.tscreateError('boom').status === 500 的断言)。

NuxtError 类还覆写了 name 的 getter,让它恒等于 "HTTPError"。源码注释解释了这一设计:h3 依赖构造函数名而非 instanceof 来识别错误,因此在 SSR 阶段抛出的 NuxtError 只有在 name 保持为 HTTPError 时才会被正确映射为对应的 HTTP 响应(见 error.ts)。这正是 createError 能够在服务器端被 h3/Nitro 正确识别的前提。

参数契约:支持字符串与对象的双入口

createError 的参数有两种形态:

  • 字符串形态createError('Something went wrong')——该字符串会成为错误的 messagestatus 默认为 500
  • 对象形态createError({ status, statusText, message, fatal, cause, data, headers, ... })——可以同时设置多个错误属性。

对象形态中可用的属性(以 NuxtErrorDetails 类型定义 为准):

属性 类型 说明
message string 面向用户的详细错误描述,建议承载多行文本、非 ASCII 字符等描述性内容
status number HTTP 状态码,范围将被钳制在 100..599,非法值回退到 500
statusText string 简短的 HTTP 原因短语(如 'Not Found'),只允许可见 ASCII 字符,用于客户端识别
cause unknown 原始错误对象,用于保留被包装错误链
data unknown(泛型 DataT 附加到错误 JSON body data 字段的自定义数据,可回传客户端
fatal boolean 客户端抛出时是否触发全屏错误页
headers HeadersInit 随错误响应一起发送的附加 HTTP 头
name / stack string 错误名与堆栈(沿原生 Error 约定)
statusCode / statusMessage number / string 已被 status / statusText 取代的废弃别名,源码中标记 @deprecated,仅用于兼容

字段的钳制与净化:源码如何保证 HTTP 合法性

NuxtError 构造器在 error.ts 中对 statusstatusText 做了两层约束,全部实现在 http-status.ts

  • sanitizeStatusCode:将状态码解析为数字后,若 NaN 或超出 100..599 范围则回退到默认值(此处为 500)。因此 createError({ status: 999 }) 这类越界输入不会产生非法 HTTP 响应。
  • sanitizeStatusMessage:通过正则 /[^\t\u0020-\u007E]/g 剔除理由短语中不允许出现的字符(即只保留水平制表符、空格与可见 ASCII 字符)。测试 error.test.ts 中传入 { statusText: 'bad\nvalue' } 的换行符正是被这一步过滤掉的。

因此官方文档反复强调的 statusText 使用规范在源码层面是有强制力的:statusText 只适合短小、符合 HTTP 规范的短语(如 "Not Found"),任何详细描述、多行文本或非 ASCII 内容都应放入 message 属性(可对照 error-handling 文档 中的 tip)。

此外,fatal 的取值逻辑也值得注意:源码中 this.fatal = details.fatal ?? !!this.unhandled,即显式传入的 fatal 优先,否则由 unhandled 推导。测试 error.test.ts 完整覆盖了这一规则:{ unhandled: true } 会得到 fatal: true,而 { fatal: false, unhandled: true } 会尊重显式的 false

在 Vue 应用中使用:SSR 与 CSR 的截然不同行为

createError 可以在页面、组件、插件、middleware 中任意使用,但同一段 throw createError() 代码在服务端与客户端的行为完全不同

  • 服务端(SSR):抛出后直接触发全屏错误页,可通过 clearError 清除错误并(可选)重定向。
  • 客户端(CSR):抛出的是非致命错误(non-fatal),交由你来处理(例如用 <NuxtErrorBoundary> 局部兜底,或自行捕获);若确实想触发全屏错误页,必须显式设置 fatal: true

典型场景:数据加载失败时返回 404

官方文档给出的电影详情页示例是最经典的用法——在 useFetch 拿不到数据时抛出带状态的 createError

<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>

这段代码在服务端渲染该页面时若 API 未返回数据,会直接进入 404 错误页流程;在纯客户端导航场景下,由于未设置 fatal,该错误默认为非致命,Nuxt 会走客户端错误处理路径(例如冒泡到 <NuxtErrorBoundary>#error 插槽)。

与错误处理体系的其他成员协同

createError 并非孤立工具,它与 Nuxt 错误处理体系的其他 API 组成了一条完整链路(详见 12.error-handling.md):

  • showError:同样基于 createError 实现(源码showError 的第一步就是 createError(error)),可直接在客户端任意时刻或服务端 middleware/plugins/setup() 中触发全屏错误页。官方建议更推荐使用 throw createError() 而非 showError
  • clearError:清除当前被处理的 Nuxt 错误,可选携带 { redirect } 跳转到"安全页面",并触发 app:error:cleared hook(见 clear-error 文档)。
  • useError:返回当前正在处理的全局错误的响应式引用,可在自定义错误页或 middleware 中读取 error.statuserror.message 等信息(error.ts)。
  • <NuxtErrorBoundary>:客户端局部错误兜底组件,阻止错误冒泡到顶层、只渲染 #error 插槽,适合"不因局部错误毁掉整个页面"的场景(见 nuxt-error-boundary.md)。
  • app/error.vue:全屏错误页的自定义入口,可通过 props 拿到 NuxtError 实例并使用 clearError({ redirect: '/' }) 恢复(详见 error-handling 错误页章节)。

错误成因传递:用 cause 保留原始错误链

当你在 try/catch 中捕获底层异常后,往往不想丢失原始错误信息。createError 支持在创建错误时传入 cause 来保留被包装的原始错误:

try {
  await fetchMovie(route.params.slug)
} catch (cause) {
  throw createError({
    status: 500,
    message: 'Could not load movie',
    cause,
  })
}

cause 的行为在开发环境与生产环境存在严格差异(这是官方文档明确的安全边界):

  • 开发环境cause 链会通过错误页的 cause 属性暴露给你(自定义 error.vue 可通过 props 读取),序列化格式为 { name, message, stack, cause },形成可递归追踪的原始错误链。原始类型(primitive)的 cause 会原样透传;其他无法序列化的值会被省略。
  • 生产环境cause 永远不会出现在错误响应或错误页 payload 中,避免将底层堆栈与内部实现细节泄露给终端用户。

这一设计在 types.tsSerializedErrorCause 类型中有明确体现。同时注意构造器中的回退取值链error.ts):当错误详情自身没有提供 status/statusText/message 时,会依次向 cause 回退取值(details.status || cause?.status),这意味着包装一个已含状态码的错误时,内层错误的 HTTP 语义会被继承。

在 API 路由(Nitro 服务端)中使用:如何把错误正确传回客户端

createError 同样适用于 server/api/ 下的 Nitro 路由处理器,用于触发服务端错误处理:

export default eventHandler(() => {
  throw createError({
    status: 404,
    statusText: 'Page Not Found',
  })
})

此时 Nitro 会把该错误转换为对应的 HTTP 响应(如 404 + statusText)。文档给出了三条在 API 路由中的关键实践建议

  1. 优先用简短 statusText:传对象时使用简短的 statusText(如 'Page Not Found'),因为 statusText 是少数能从服务端透传到客户端的字段;反之,在 API 路由里传给 createErrormessage 不会传播到客户端。
  2. 需要回传自定义数据就用 data:可以借助 data 属性把结构化业务数据返回给客户端。当前端使用 useFetch 处理该错误时,自定义数据位于 error.value.data.data(第一层 .data 是 h3 错误 JSON 的 data 字段,第二层才是你传入的内容)。
  3. 警惕消息注入:无论如何,都应避免把动态用户输入拼进 message,防止潜在的安全问题(如日志注入 / 响应拆分)。

服务端与前端互通的底层实现:从 NuxtError 到 h3 的完整链路

将上文串联起来,可以看到 createError 是全栈错误链路的枢纽。从源码与测试可以还原出它的完整工作流:

  1. 你在页面/组件/API 路由中调用 createErrorthrow,得到一个 name === 'HTTPError'、携带 status/statusText/dataNuxtError 实例。
  2. 若发生在 Nitro 服务端error.test.ts 验证了 HTTPError.isError(error) === true——NuxtError 能被 h3 识别并映射成正确的 HTTP 状态码与响应头。
  3. 若发生在 SSR 渲染阶段,Nuxt 渲染管线识别出致命错误后,会渲染 app/error.vue(或在请求头接受 JSON 时返回 JSON 响应)。
  4. 错误进入 payload 后经由序列化(toJSON(),见 error.ts,其 key 固定为 ['status', 'statusText', 'unhandled', 'message', 'data'])与反序列化还原,前端 useError()/useFetch 中的 error.value 即为一个可安全读取的 NuxtError
  5. 前端需要恢复时调用 clearError({ redirect }),重置错误状态、触发 app:error:cleared hook,并按需路由跳转。

整个链条中,NuxtError 与 h3 的 HTTPError 在字段语义上的等价性由 error.test.ts 以一组等价输入做了逐字段断言(包括 statusstatusTextmessagedatabodyunhandledtoJSON() 输出),这保证了"同一个 createError 对象在 Vue 端与 Nitro 端表现一致"这一全栈承诺是有测试兜底的。

小结与最佳实践清单

  • createError 接受字符串(作为 message,状态默认 500)或对象;对象形态可携带 status/statusText/message/fatal/cause/data/headers 等元数据。
  • 服务端抛出触发全屏错误页(用 clearError 恢复);客户端抛出默认非致命,需要全屏页须设 fatal: true
  • statusText 只放简短短语(会被净化器过滤非法字符),详细描述一律进 message;越界状态码会被钳制回 500
  • cause 保留原始错误链——开发环境可在错误页追溯 { name, message, stack, cause },生产环境一律不下发。
  • API 路由中推荐 statusTextdata 回传结构化信息(useFetch 下读取 error.value.data.data),不要把动态用户输入拼进 message
  • 更完整的全屏错误页定制、vue:error hook 与 <NuxtErrorBoundary> 局部兜底等场景,可继续阅读 Error Handling 章节useErrorshowError 的专项文档。
登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.14 K
2.75 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
857
1.35 K
docsdocs
暂无描述
Markdown
898
5.82 K
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
921
1.84 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.8 K
1.02 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
531
596
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.02 K
519
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.36 K
1.46 K
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
548
391