现在前后端沟通的方式大多应该是基于 http 的序列化使用 json 的请求, 规范往往会使用 Restful. 然而程序大多数时间都是在处理异常, 但是错误信息组织方式却千奇百怪, 这里简单说一下我自己的理解.

有人会说, http 状态码 很多时候已经可以当做错误信息了, 也就是返回 body 可以不包含太多信息, 当然可以这样, 但是当我们的业务如果不只是基于 http, 例如 ws, 基于返回状态码的方式将不再适用, 所以我们应该在初期制定一个较为通用的适合自己的规范.

1. 错误响应类型:

interface Error {
  code: string
  message: string
  messages?: string[]
}

code 为错误信息码, message 为错误信息详情, messages 为错误信息补充信息(例如: 参数校验错误详情).

也可以加入 statusCode, 适配非 http 请求.

2. 错误响应状态码不该为 2xx:

如果使用过一些流行的 http cliet 库, 例如 JSaxios, 就会了解到 非2xx 的请求会被当做 error catch 到. 因为一般来说 2xx 的含义是正常响应, 也就是说流程可以正常进行, 因此我们应该让客户端拿到 2xx 的时候可以自信得走正常流程.

相对的, 有些人喜欢只要服务端不挂, 响应状态码都会是 200, 数据格式是这样的:

interface Response {
  ok: boolean
  data: any
  error: any
}

也就是无论如何, 客户端都需要先检查 ok 字段或者 error 字段. 这样做会带来一些问题, 首先返回会在正常响应中冗余额外数据; 其次有时候可能会失误导致 ok 和 error 不一致; 最主要是客户端没办法做到信任, 一些全局的错误处理也没法做(比如: catch 到 401 跳到登录页).

3. code 应做到含义清晰唯一:

code 一般会作为客户端收到 error 之后第二个检查的字段(第一个为 statusCode). 所以我们应该尽可能多得将信息传递给客户端.

一般建议 code 类型使用 string 常量, 除非觉得状态码比较隐秘, 可以使用数字, 通过内部状态对照表查看, 但是使用数字时, 要避免和 http 状态码 重复.

其次, 错误码应该做到全局唯一, 也就是不要出现相同的错误码在不同的接口下含义不一, 这样会造成很多开发者负担以及维护负担.

还有, 错误码应为常量, 绝对不能将多语言做在错误码中.

4. message 应当简洁明了:

message 作为错误码的补充, 应当简洁明了, 某些时候其实是不必要的, 有些时候也可以用作客户端显示信息.

5. messages 应当尽可能包含全部信息:

messages 作为最后一个属性, 需要包含剩下的所有信息, 最常用的就是用作显示参数校验错误详情.

6. 尽可能得少暴露服务端状态:

对于 5xx 的错误, 或者预期之外的错误, 应当尽可能得少暴露信息, 不要返回任何详情.