跳到主要内容

Feathers.js 错误处理要停在什么边界

· 阅读需 3 分钟
一介布衣
全栈开发者 / 技术写作者

Feathers.js 写着写着,大家迟早会遇到一个现实问题: 错误到底该在 hook 层拦,还是在 service 里抛,还是统一让框架接住以后再返回前端。

如果这个边界不清楚,项目很快就会出现两种麻烦。一种是同类异常返回结构不一致,前端很难稳定处理;另一种是 service 里开始到处塞 try/catch,读起来特别累。

先把异常分成三类

我比较习惯把异常分成:

  • 业务异常,例如文章状态不允许发布
  • 权限异常,例如当前用户没有编辑权限
  • 系统异常,例如数据库连接、第三方依赖超时

只有先分好类,后面才谈得上应该在哪一层处理。

service 负责抛出可理解的业务错误

service 层最适合表达“这件事为什么不能做”。比如文章已经归档,不允许再次编辑;比如库存不足,不允许继续下单。这些属于业务语义,最好由 service 明确抛出,而不是模糊地返回一个 false

这样做的好处是,任何入口只要调用这个 service,都能得到一致结果,不会因为接口路径不同而表现不同。

hook 更适合承接横向错误

认证失败、参数不合法、角色不满足,这些更像入口层问题。它们往往在真正进入核心业务前就应该被挡掉,所以更适合放到 before hook 或 schema 校验里。

这类错误如果进了 service 再判断,service 本身就会被“入口噪音”污染。

不要为了兜底把所有错误都吞掉

有些人会在 service 外层包一层大 try/catch,最后统一返回“操作失败”。这看似安全,实际上会带来两个副作用:

  • 前端拿不到足够明确的错误语义
  • 排查日志时只剩一堆模糊提示

更稳的办法是,预期内的错误正常抛出带语义的异常,非预期错误让日志系统完整记录,再由统一错误中间件格式化输出。

前后端约定比花哨封装更重要

到了 2021 年,大部分管理后台前端都希望拿到稳定的错误码、错误消息和字段级提示。如果后端今天返回字符串,明天返回数组,前端表单体验就会很差。

所以与其设计复杂异常体系,不如先把最常见的几种错误结构定住。Feathers 帮我们省的是框架层劳动,接口约定还是得自己守。

小结

Feathers.js 的错误处理要好用,关键不是“哪里都 catch 一遍”,而是让业务错误留在 service,入口类错误留在 hook,真正的系统问题交给统一日志和错误出口。边界一旦站稳,接口行为会明显稳定很多。