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