背景:
我们提供一个 SDK ,有很多 API 供上层应用使用。每次 API 变更都要考虑前向兼容,不能影响已有应用(否则代价巨大)
问题: 假设我有一个 API ,设为 DoA ,当 DoA 出现异常的时候,会通过另一个回调函数 OnError(err)返回错误信息给上层应用。 假设前期的错误码回调设计是这样的( err 是个结构体,包含 code 和字符串):
{1001, "原因 1"},
{1002, "原因 2"},
{1003, "原因 3"}
最近有部分用户提出来,部分错误码设计不合理:原因 2 太粗,需要细化为原因 2a ,2b ,2c 。需求是合理的。
那这个时候整个 OnError 的错误码回调应该如何设计呢?(即能精细化错误码,又要保证前向兼容) 当前想到的几个方案:
方案 1: 直接新增 code 和错误码字符串,
{1001, "原因 1"},
{1002, "原因 2"},
{1003, "原因 3"},
{10021, "原因 2a"},
{10022, "原因 2b"},
{10023, "原因 2c"},
问题:会导致原来只判断 1002 的应用不兼容
方案 2: 新增 code 和错误码字符串,当出现 2a 导致的错误时,回调两次,把 1002 和 10021 都回调一下 问题:上层应用不一定能接收两次回调,或者可能导致上层应用出现一些时序相关的奇怪问题
方案 3: 不新增 code ,通过不同的字符串来标识精细化的错误信息。类似这样:
{1001, "原因 1"},
{1002, "原因 2a"},
{1002, "原因 2b"},
{1002, "原因 2c"},
{1003, "原因 3"},
问题:对开发者不太友好,因为他还需要去解析字符串。。。
大家看下是否有更好的设计?
![]() |
1
sujin190 58 天前
感觉比较好的方式是添加一个 error_details 数组结构化字段,里边详细包含各种细节错误信息,一级的 error_code 只用来表示错误大类别,一般来说 error_code 决定大业务流程方向,在保证 error_code 能完整完成业务流程情况下,error_details 提供细节优化,实际情况下就算后续 error_details 进行调整了不兼容也能保证业务流程能正常完成,只不过纠错、提示或者交互不那么优化而已,毕竟大的业务流程总不能说改就改吧,否则你这兼容性感觉没法弄
|
2
iOCZS 58 天前
一般错误有个域的概念,域下面才细分具体的情况,域可以用一个数据范围代替,譬如说 11000-11999 都是某个类型的错误
|
![]() |
3
BiChengfei 58 天前
方案二吧,新增加一个字段,例如原字段:code ,新字段 codeDetail 。只是不明白为啥方案二要分两次回调
|
![]() |
4
13240284671 58 天前
v1,v2 版本
|
![]() |
5
Curtion 58 天前
你的三个方案都要求上层应用做修改才行,这也没有兼容上啊。看起来发布新 SDK 就行, 需要的人更新不需要的人继续用旧版,想升级的人也改(反正他们都得改)
|
6
ntower 58 天前
话说你这是向后兼容吧
|
![]() |
7
javalaw2010 58 天前
新增一个 subcode
|
![]() |
8
gaobh 58 天前 via iPhone ![]() 大部分都是提供 v1 v2 接口,老接口不断,直到大部分人都迁徙
|
![]() |
9
zhuisui 58 天前
首先:你这是向后兼容,不是向前兼容。。。
|
10
xFrank OP @sujin190 error_details 添加在哪里啊?
@BiChengfei 因为要给老应用回调老 code ,新应用回调新 code @Curtion 方案 3 可以兼容老的,因为从开发角度看,一般人 if else 里面写的都是 code ,那个字符串都是用来打印提示信息的。方案 3 就要求新的应用纪要判断 code ,也要提取字符串里面的信息来做更多的判断 另外,澄清下,这个场景比较特殊,只要有升级,所有应用都只能跑最新版本。。。 |
12
ilvsxk 58 天前
抛弃用 int 来定义 error code ,用字符串,用 . 来表示业务层级关系,比如:{ "error": "order.edit.network_error"} {"error": "order.edit.no_auth"} ,既表意,又能扩展,也有层级关系。
|
![]() |
14
whoosy 58 天前
影响面最小的修改就是方案三
|
15
vacuitym 58 天前
不如增加一个二级的 code 和 msg
|
16
linauror 58 天前
推荐 sub_code 的形式
|
![]() |
17
magicls 58 天前
我多问一句,你写的
``` json {1001, "原因 1"} ``` 这是你简写了,还是说就是这样的?因为我理解接口再怎么烂,它不应该都是 ``` json {"code":1001, "message":"原因 1"} ``` 这样吗? |
18
ZZ74 58 天前
建议用 3 ,问题本质是错误原因定义太宽,2a 2b 其实就是不同错误
|
20
renmu 58 天前 via Android
以前没考虑到,那现在不管你怎么改都会改变原来的语义,那就不要改了,留着以后 v2 大版本不兼容再动
|
21
esee 58 天前
好麻烦,就算我提供了兼容的 api ,也不知道使用者对返回的结果是怎么使用和判断的,可能又会引发问题。
所以涉及到返回结果数据结构需要变动的话,我都是直接接口 V1 ,接口 V2.。。这样写新的。。 |
![]() |
22
BiChengfei 58 天前
就 subcode 方案,我也是这个意思
|
![]() |
23
ryanking8215 58 天前
为啥不能 {1004: "2b"}
|
24
dddd1919 58 天前 ![]() 设计 APIv2 ,用新设计的 code ,然后给 APIv1 打上 deprecated ,备注迁移说明
|
![]() |
25
cowcomic 57 天前
如果结构体就是发出来这个样子,可以改成下面的形式
``` {1002, "原因 2b", "errorCodes": [1002, 100202], "msg": "原因 2b"} ``` 1002, "原因 2b" // 这部分就给原来的系统用 "errorCodes": [1002, 100202], "msg": "原因 2b" // 新系统用这部分,原来系统如果能迭代的话,逐渐改为这种 "errorCodes": [1002, 100202] // 这个结构留着以后细化 code 用 如果新结构想再增加扩展性,不同 codes 不同 msg ,外面再封一层数组 想再再再增加扩展性,参考 Java 的 Exception 对象 |
26
dyllen 57 天前
像楼上说的在原来的基础上增加子级错误码和消息,例子有支付宝也是这样干的,有两级,我接过好几个支付相关的接口都是如此。
|