前端进阶之旅前端进阶之旅
  • 基础篇HTML/CSS/JS 打底
  • 进阶篇原理与工程化
  • 高频篇面试最常问的那批
  • 精选篇按模块收敛的总结
  • 手写篇常考代码手写实现
  • 面经篇真实面试问题复盘
  • AI 篇NEWAI 时代的前端考点
  • 历年面经NEW按年份追踪真实考点
  • 每日一题每天一道,攒手感
  • 专项自测100 题快速查漏
  • 小程序题库小程序专项刷题
  • 算法题库NEW在线编码即时判题
  • 知识卡片NEW碎片时间过考点
  • 面试题大全常见问题解析
  • AI 答疑NEW随时提问,即时解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • AI 定制路线NEW按你的简历现排
  • AI 知识地图NEW串起全站知识点
  • 原理篇React / Vue 源码拆解
  • HTTP从报文一路讲到 HTTPS
  • 浏览器渲染、事件循环、进程
  • 计算机基础Linux、网络、操作系统
  • 设计模式23 种模式怎么用
  • Node学习指南从环境搭建到服务端
  • NPM工作流script、依赖与发布
  • Docker容器化部署上手
  • Canvas图形与动画实战
  • 前端系统进阶学习大型项目工程化
  • 前端综合文章长期沉淀的实践文
  • 思维导图知识点全景图
  • 学习路线按图索骥不跑偏
  • AI 热点NEWAI 每日动态
  • 公众号动态公众号历史文章
  • 博客动态站长的技术博客
  • 开发者导航常用工具与文档站
  • 基础篇HTML/CSS/JS 打底
  • 进阶篇原理与工程化
  • 高频篇面试最常问的那批
  • 精选篇按模块收敛的总结
  • 手写篇常考代码手写实现
  • 面经篇真实面试问题复盘
  • AI 篇NEWAI 时代的前端考点
  • 历年面经NEW按年份追踪真实考点
  • 每日一题每天一道,攒手感
  • 专项自测100 题快速查漏
  • 小程序题库小程序专项刷题
  • 算法题库NEW在线编码即时判题
  • 知识卡片NEW碎片时间过考点
  • 面试题大全常见问题解析
  • AI 答疑NEW随时提问,即时解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • AI 定制路线NEW按你的简历现排
  • AI 知识地图NEW串起全站知识点
  • 原理篇React / Vue 源码拆解
  • HTTP从报文一路讲到 HTTPS
  • 浏览器渲染、事件循环、进程
  • 计算机基础Linux、网络、操作系统
  • 设计模式23 种模式怎么用
  • Node学习指南从环境搭建到服务端
  • NPM工作流script、依赖与发布
  • Docker容器化部署上手
  • Canvas图形与动画实战
  • 前端系统进阶学习大型项目工程化
  • 前端综合文章长期沉淀的实践文
  • 思维导图知识点全景图
  • 学习路线按图索骥不跑偏
  • AI 热点NEWAI 每日动态
  • 公众号动态公众号历史文章
  • 博客动态站长的技术博客
  • 开发者导航常用工具与文档站
首页程序员面试题库Next.js Server Actions 错误分类 业务错误与系统错误区分
NeNext.js全栈边界

当 Server Actions 抛出错误时,客户端如何区分可恢复的业务错误与不可恢复的系统错误?

服务端抛出带类型标识的错误对象,客户端捕获后依据错误码或类型字段区分可恢复业务错误与不可恢复系统错误,分别提示与上报。

前端进阶之旅 · 一题精讲更新于 2026.09.05
Next.js#全栈边界
先看核心答案读代码示例
理解线索

错误分类标识

  1. Error 子类继承 Error 并设置 name,作为类型标记
  2. 业务错误携带 code 与可重试信息,面向用户
  3. 系统错误只含通用信息,避免泄露内部细节

跨网络后原型链丢失,客户端只能依赖 name 或自定义属性判断类型。

核心回答

先记住这个答案

在服务端定义继承自 Error 的 BusinessError 与 SystemError,并设置各自固定的 name 属性(如 'BusinessError' 和 'SystemError')。业务错误携带具体 code 与可重试标记,系统错误只含通用信息。客户端 catch 时检查 error.name 或 error.code 进行分流:若为业务错误,则展示友好消息并允许用户修改后重试;若为系统错误,则记录日志并跳转通用错误页。注意:跨网络序列化后 Error 原型不保留,因此不能使用 instanceof,只能通过 name 或显式字段判断。

  • 用 Error 子类并设置固定 name 标识
  • 客户端按 error.name 或 code 分类处理
  • 系统错误需隐藏细节并上报记录

错误类型标记与客户端识别机制

在 Server Actions 内部,可预先定义多个继承自 Error 的错误类,每个类在构造函数中设置自己的 name 值,例如 BusinessError 的 name 固定为 'BusinessError',SystemError 固定为 'SystemError'。业务错误还可以携带业务码 code 和 retryable 布尔值,便于客户端决定交互方式;系统错误则只提供通用 message,不暴露堆栈或数据库细节。

当 Server Actions 抛出错误时,Next.js 会将错误对象序列化并传回客户端。由于序列化仅保留可枚举属性与 name、message 等标准字段,prototype 会丢失,因此 error instanceof BusinessError 必然返回 false。客户端必须采用 error.name === 'BusinessError' 或检查 error.code 的方式分类,这种约定式标记被 Next.js 官方实践广泛采用。

客户端分类处理示例JavaScript
// 服务端定义并抛出(伪代码)
// class BusinessError extends Error {
//   constructor(code, message) {
//     super(message);
//     this.name = 'BusinessError';
//     this.code = code;
//     this.retryable = true;
//   }
// }

// 模拟客户端收到的已序列化错误对象
const receivedErrors = [
  { name: 'BusinessError', message: '余额不足', code: 'INSUFFICIENT_BALANCE', retryable: true },
  { name: 'SystemError', message: '数据库连接失败', code: 'INTERNAL' }
];

function classify(err) {
  if (err.name === 'BusinessError') {
    console.log(`业务可恢复:${err.code},请修改后重试`);
  } else if (err.name === 'SystemError') {
    console.log(`系统不可恢复:${err.code},已上报并跳转通用页`);
  } else {
    console.log('未知类型,按系统错误处理');
  }
}

receivedErrors.forEach(classify);
查看输出与解释
业务可恢复:INSUFFICIENT_BALANCE,请修改后重试
系统不可恢复:INTERNAL,已上报并跳转通用页

代码模拟了跨网络后错误对象只有 name/code 等属性,客户端通过 name 或 code 正确分流。

用户提交订单时的错误区分场景

假设用户在线支付创建订单,Server Actions 调用下单 API。当用户余额不足时,服务端抛出 BusinessError,code 为 'INSUFFICIENT_BALANCE',并设置 retryable 标记为 true。此时客户端捕获后弹出可读提示,建议用户充值或更换支付方式,且表单数据和用户在中断处的输入不会丢失,允许用户修改后再次提交。

若下单过程中数据库连接池耗尽抛出系统异常,则服务端抛出 SystemError,客户端 catch 到后自动引导用户到错误页,同时通过上报接口将错误 digest 提交到监控系统。这样既避免向用户展示技术堆栈,也便于研发定位问题,同时不重复提交相同请求造成脏数据。

跨边界序列化导致的分类失效条件

最容易失效的地方是开发者尝试使用 instanceof 判断错误类型,因为 Server Actions 错误经过 Next.js 的序列化管道后,原始 prototype 完全丢失。即便服务端抛出的是自定义 Error 子类,客户端接收到的也只是一个普通对象,其 name 属性虽然保留,但 instanceof 永远返回 false。因此必须约定使用 name 或额外字段,而不是类实例。

另一个风险是 Error 对象中携带不可序列化属性(如函数、Symbol)会在传递时被剥离,导致某些细节丢失。应对措施:在服务端抛出前将必要字段整理为可序列化标量(字符串或数字),并限制 message 长度。如果需要完整的服务端堆栈,应将原始错误记录在服务端日志中,而不是依赖客户端回传。

回答前,多想一步

容易答错的地方

用 instanceof 判断错误类型
不少文章建议使用 error instanceof BusinessError 区分业务错误,但在 Server Actions 中错误被序列化传递,原型链已经丢失,该判断永远为 false。正确做法是基于 error.name 或自定义 code 字段。测试时应模拟实际序列化后的对象。
把系统错误的堆栈直接展示给客户端
有些实现会把原始 Error.message 直接传给用户,导致数据库结构、内部服务名等泄露。系统错误必须在服务端捕获并替换为通用提示,原始错误记录到服务端监控,客户端只收到一个稳定的 digest 或通用信息。
试着用自己的话回答

面试官还会怎么问?

Server Actions 返回错误后,客户端表单状态应如何保留以支持重试?

可以通过 useActionState 管理表单状态,BusinessError 发生时保留用户输入和错误信息,在组件内直接展示;SystemError 时不保留继续操作,跳转到错误边界。重试动作仅对业务错误开放。

如果服务端抛出的不是 Error 对象而是普通对象,客户端如何处理?

只要能按约定区分 name 或 type 字段即可。但建议统一使用 Error 子类并设置 name,因为 Error 对象包含 message 和堆栈便于服务端日志。若抛普通对象,需要自行处理堆栈丢失问题。

系统错误在客户端被捕获后,用什么策略避免用户重复触发相同请求?

客户端可在 catch 中记录已请求标记并使用防重复提交逻辑;同时服务端在接口入口做幂等校验,如携带幂等键。系统错误发生时禁止自动重试,只允许用户手动刷新。

从一道题,走向一组知识

把知识连起来

全栈边界

Server Actions 执行后,为何客户端状态可能不会自动更新?如何确保依赖数据同步?

同属「全栈边界」专题,接着看 Next.js Server Actions 客户端状态同步 数据更新 不自动刷新 在具体场景中的处理方式。

全栈边界

在表单中使用 Server Actions 时,如何正确处理多步提交流程中的状态管理?

同属「全栈边界」专题,接着看 Next.js Server Actions 多步表单 状态管理方案 在具体场景中的处理方式。

参考资料

  • App Router

示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。

本题目录
  1. 先记住这个答案
  2. 错误类型标记与客户端识别机制
  3. 用户提交订单时的错误区分场景
  4. 跨边界序列化导致的分类失效条件
  5. 容易答错的地方
  6. 面试官还会怎么问
  7. 把知识连起来
读懂,再试着讲出来

先看核心答案,再读代码。最后展开追问,检查自己有没有遗漏边界。

试着回答追问
浏览全部面试题理解原理,也关注真实的使用场景。回到顶部 ↑