一、什麼是錯誤碼
錯誤碼一般情況分為對外錯誤碼,系統内部錯誤碼。
對外錯誤碼常應用在一些開放接口,比如http接口,rpc接口等,通過錯誤碼的形式給予上遊更加友好的錯誤提示以及錯誤描述。
系統内部錯誤碼,存在于關系緊密的微服務之間、或者程式的上下遊中。因為某種業務錯誤、或者系統不可用造成的錯誤,開發人員可以根據錯誤碼、錯誤資訊進行具體定位;或者根據上遊根據錯誤碼做業務邏輯判斷,進而保證整體流程完整性。
總而言之,錯誤碼的作用: 指出錯誤的原因,快速定位問題,指導上遊系統做出正确的業務判斷,引導使用者進行正确的操作。是以建構一個通用且架構清晰的錯誤碼體系是一件很有必要的事情。
那麼怎麼定義一種對外對内都友好的錯誤碼呢?至今業内也并沒有一個比較好的方案或者規範。這裡結合新老支付系統融合,逐漸進行摸索。
二、支付系統錯誤碼現狀
由于曆史原因,公司内部目前有兩套運作中的錢包系統。為了提高錢包系統可用性以及性能,對兩套錢包系統進行遷移整合更新優化。但遷移合并兩套錢包系統的途中,發現兩套錢包系統、以及之前現存的已經優化過的錯誤碼之前存在沖突、類型不一緻、定義混亂、随意性高等問題。
由于其一錢包系統之前由其他團隊開發維護,後期也對其進行重構過,這造成了新錢包系統的錯誤碼定義規則存在兩套;從代碼角度來看,新老錢包系統在設計之初的時候,對錯誤碼的定義都各自定義了一個比較合适的規範,但是在後期開發維護中,越來越少的開發人員去遵循規範定義錯誤碼,最終造成了由錯誤描述決定錯誤碼的現象。而目前新系統中錯誤碼,在設計之初,并未考慮到未來整合帶來的錯誤碼沖突等問題,造成了部分錯誤碼重合,語義大相徑庭的問題,是以重新定義錯誤碼規範也是迫在眉睫。
錢包系統錯誤碼現狀:
錢包一錯誤碼定義: 6位錯誤碼。 首位表示錯誤類型,區分系統級别、校驗、rpc服務調用錯誤。 這種設計方式,第一位是明确的,後面5位都是預留的錯誤碼,長度足夠,滿足後續錯誤碼的增加;缺點錯誤碼對應的類型太少,會出現相同語義的錯誤碼,對應不同的首位數字。後重構版本的錯誤碼修改了原有的錯誤碼位數,修改後7位。造成了該系統的接口層,6位錯誤碼,7位錯誤碼混亂,并且錯誤碼沒有分類,全部順序後排。
錢包二錯誤碼定義: 提供錯誤碼工具類,規定了大多數錢包常用的錯誤碼;然後以此為基礎,進行增加。優點: 錯誤碼分類清晰,結構明了,缺點: 不容易根據錯誤碼定位具體錯誤。
簡單來說,目前錢包系統錯誤碼存在以下問題
1. 錯誤碼字段類型定義不一緻。有的定義數值類型,有的定義字元串類型
2.錯誤碼重合問題。相同的錯誤碼,在不同系統中有着不同的語義
三、調研業内接口定義
鑒于目前支付系統錯誤碼的痛點,如錯誤碼應該用數值類型還是字元串類型,長度命名格式是怎樣的等問題,調研了多家大廠的API規範以及接口定義,來探索适用于支付系統的錯誤碼規範。
- 微信支付
a. 參考微信支付v2接口
微信支付v2接口: 協定:http, content-type: text/xml
參考連結: https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1
原格式是xml,為了更加直覺,這裡先加工為json格式
{
"return_code":"SUCCESS", // SUCCESS/FAIL 此字段是通信辨別,非交易辨別,交易是否成功需要檢視result_code來判斷
"return_msg":"OK",
"result_code":"SUCCESS", // SUCCESS/FAIL 辨別業務成功失敗
"err_code":"SYSTEMERROR", // 當result_code為FAIL的時候,該值傳回業務錯誤碼
"err_code_des":"系統錯誤"
}
微信支付錯誤碼結構為三級結構:
一級、公共錯誤碼(網關層) 。該層僅傳回通信成功失敗資訊
二級、業務錯誤碼 (總): 表示該業務是否處理成功
三級、具體業務錯誤碼
業務錯誤碼舉例:
error_code | err_code_des |
NOAUTH | 商戶無此接口權限 |
INVALID_REQUEST | 參數錯誤 |
NOTENOUGH | 餘額不足 |
b.參考微信支付v3接口
微信支付v3接口: 協定:http, content-type: application/json
參考連結:
err_code | http_code | err_msg |
USERPAYING | 202 | 使用者正在付款中 |
OUT_TRADE_NO_USED | 403 | 商戶訂單号重複 |
ORDERNOTEXIST | 404 | 訂單不存在 |
根據微信v3的接口文檔可知,微信支付傳回的業務錯誤的同時,會傳回一個與之對應的httpcode。當http_code的狀态碼在[200,300)之間,認為該請求是有合法的傳回的;當大于300時,判斷接口傳回一定是有異常錯誤的。微信支付V3 sdk封裝了http_code與err_code的相關處理。
對外暴露http接口,在抛出業務錯誤的同時,也要抛出相同語義的httpcode,這就需要開發人員明确httpcode語義。 這樣的劣勢在于學習成本較高,依賴開發人員對httpcode的熟練程度,可能會出現 httpcode語義與業務錯誤語義不一緻的現象。
2.支付寶錯誤碼定義
參考連結: https://opendocs.alipay.com/open/common/105806
不同業務的業務錯誤碼: 舉一個接口的例子 https://opendocs.alipay.com/apis#%E4%B8%9A%E5%8A%A1%E9%94%99%E8%AF%AF%E7%A0%81
sub_code、sub_msg這兩個參數辨別支付寶傳回的業務錯誤碼、業務錯誤資訊;
{
"code":"",//網關傳回碼
"msg":"",//網關傳回碼
"sub_code":"ACQ.INVALID_PARAMETER",
"sub_msg":"參數無效"
}
支付寶的錯誤碼定義 與 微信支付的v2接口定義風格比較相像。
支付寶錯誤碼結構分為兩級: 一級: 網關, 二級: 業務錯誤碼。
請求支付寶接口,先通過支付寶網關系統,網關系統進行驗簽、加解密、流控等功能,如果網關校驗出錯,則抛出公共錯誤碼。網關校驗成功之後,交給下遊業務系統,sub_code都是語義明确的錯誤碼,以及錯誤描述。
3. google Api規範
參考連結:
google的錯誤碼定義中,将傳回碼的結構定義為
message Status {
// A simple error code that can be easily handled by the client. The
// actual error code is defined by `google.rpc.Code`.
int32 code = 1;
// A developer-facing human-readable error message in English. It should
// both explain the error and offer an actionable resolution to it.
string message = 2;
// Additional error information that the client code can use to handle
// the error, such as retry delay or a help link.
repeated google.protobuf.Any details = 3;
}
其中 code: 是錯誤碼,message: 是具體的錯誤資訊,detail是根據這個錯誤,推薦調用方采取怎樣的措施。
google對于錯誤碼的定義,是比較簡潔的。一個大類配置設定一個code;并不會因為多個相似的錯誤類型提供多個code。
google規範裡details資訊: 表示該錯誤的具體原因,定義參考:
detail裡面定義了 retryable資訊 可以表示該錯誤碼傳回是可以進行重試的,并且給出推薦的重試延遲時間、QuotaFailure資訊表示配額出錯、限流超限等;badRequest可以詳細的給出為什麼會報這種錯誤 等等開發人員可以根據這樣詳細的錯誤傳回碼作出正确的反應。
4. 微網誌 規範
參考api:
{
"request" : "/statuses/home_timeline.json",
"error_code" : "20502",
"error" : "Need you follow uid."
}
20502 其中 錯誤碼的組成: 1位 錯誤級别編号(系統、服務) + 2位服務子產品(比如 網關、微網誌、評價、私信 比較像服務辨別) + 2位 錯誤代碼(自定義的錯誤編碼)
2 | 05 | 02 |
服務級錯誤(1為系統級錯誤) | 服務子產品代碼 | 具體錯誤代碼 |
微網誌的錯誤碼有明确的結構語義。将服務系統辨別,顯示在錯誤碼中。這個操作與支付寶錯誤碼構成有一點相像。第一位 辨別服務級、系統級的字段,不确定是否是表示該錯誤是有網關抛出、還是說明确幾種系統級别的錯誤,按分類抛出。
5.阿裡巴巴的JAVA技術手冊
阿裡巴巴規範
第一點: 說明了錯誤碼的特點: 要簡單明了;
第二點: 錯誤碼最好定義為string字元串類型: 來源 + 錯誤編号 (這樣,錯誤碼的數值可以攜帶更多的資訊)
第三點: 避免随意添加錯誤碼、避免直接暴露錯誤碼給到使用者側
綜上所述, 通過調研的這幾家的對外文檔來看,錯誤碼的定義業内并沒有一個統一的規範。但是大體的設計思路如下:
a. 錯誤碼類型為字元串類型
b. 系統如果由網關→ 内部服務構成,則錯誤碼分為兩級
c. 錯誤碼可以辨別出抛出錯誤的來源服務。
d. 錯誤碼可以抽象出來兩種 公共錯誤碼、業務錯誤碼
四、思考與結論
結合上述調研的行業錯誤碼定義,以及目前錢包系統現狀。由于支付系統處于整體業務流程的最基礎層,提供支付、付款等RPC能力,不存在直接對外暴露http接口的可能。是以微信支付、支付寶支付的三層錯誤碼結構并不适用于錢包系統。
借鑒上述調研的api,錯誤碼定義成字元串類型,更适用于業務場景,友善于後期的業務擴充。而google規範中對于錯誤碼場景定義的統一規範,在一定程度上又降低了開發人員随意定義新錯誤碼的可能。是以在error_code的場景定義上參考google-api規範
錯誤碼error_code: 字元串. 前N位為目前業務所屬領域辨別,優勢: 易于區分其他業務錯誤碼,如果後期由于業務擴充、或者業務縮小帶來的服務拆分合并,錯誤碼仍然可以保持目前的設定。
提取公共常用的錯誤:
參考google規範進行歸集: https://github.com/googleapis/googleapis/blob/master/google/rpc/code.proto
RPC接口常用錯誤 | error_code |
内部錯誤 | 115 |
該請求不支援 | 112 |
狀态錯誤 | 110 |
請求頻繁 | 109 |
沒有權限類錯誤 | 108 |
權限校驗錯誤 | 107 |
已存在類錯誤 | 106 |
不存在類錯誤 | 105 |
逾時類錯誤 | 104 |
參數錯誤 | 103 |
未知錯誤 (比如調用下遊接口出錯,可以抛這個異常) | 101 |
其他業務錯誤碼,可以使用200~999錯誤段進行自定義設定;但是如果有錯誤語義命中上述錯誤,則需要優先選擇上述錯誤碼。
五、RPC錯誤碼結構定義
exception RpcError{
1:required string err_code;
2:required string err_desc;
}
- 錯誤碼定義:
構成: 業務+錯誤碼類型+自定義業務編碼; 其中自定義業務編碼是系統自定義的。
辨別處理業務 | 錯誤碼類型(3) | 自定義業務編碼(2) |
參數校驗失敗:
{
"err_code":"WORDER.10501",
"err_desc":"交易不存在"
}
WORDER:表示目前錯誤發生時,所處理的業務辨別
105: 不存在
01: 交易不存在
02: 使用者不存在
03: 訂單不存在
...
2. err_desc: 錯誤資訊
錯誤資訊 開發人員可以快速定位問題。
3. 錯誤要抛出來
接口如果處理出錯了,包裝好合适的錯誤碼以及錯誤描述,将該錯誤throw出,而不是将錯誤包在接口傳回參數中。由于公司使用的是thrift協定-http,并且監控告警強依賴于httpCode,将錯誤直接抛出去,可以使監控更加有效的監控RPC接口,避免處理出錯,但是傳回httpcode是200的場景。
六、網關類型的httpcode設計
- httpcode基礎
錯誤碼 | 代表含義 |
2xx | 成功 |
3xx | 重定向 |
4xx | 用戶端原因引起的錯誤 |
5xx | 伺服器原因引起的錯誤 |
2. http服務傳回
{
"code":"0", // 成功:0 失敗:傳回對應錯誤碼
"message":"",
"data":{ //接口實際處理結果
},
"pagination":{
"is_end":false,
"is_first":true,
"offset":20,
"limit":20,
"total":1000
}
}
3 錯誤資訊轉換
http接口,如果接口傳回成功。則httpcode錯誤碼傳回200;如果失敗,可以按需傳回上述httpcode。
http接口一般分為兩種,第一種: 内部http接口; 第二種,與前端進行互動。内部http接口,錯誤碼可以參照rpc接口;外部接口,避免将内部錯誤碼外露出去,對使用者展示的錯誤描述,最好可以在http層進行轉換,不要将内部錯誤描述直接暴露出去。
七、展望
在系統遷移、重構、優化的時候,經常會遇到由于原有系統設計不合理,後續趕時間堆需求,造成的系統日益難以維護的問題。本次主要針對遷移過程中,遇到的錯誤碼定義混亂這一問題,提出調研、以及自己的思考。目标能夠統一錯誤碼格式的規範,以及rpc、http類型接口的錯誤定義規範。在後續系統遷移過程中,使用規範的錯誤定義,降低上遊系統了解錯誤的複雜度,并且在一定程度上可以降低運維效率。
在後續的規劃中,針對規範的錯誤碼使用,可以有更多的技術設想,比如錯誤內建SDK,内部包含錯誤碼定義,以及錯誤的打點上報,錯誤監控大盤等。
作者:任我去留
出處:https://zhuanlan.zhihu.com/p/411726319