錯誤碼


關於錯誤碼的那點事 - 知乎 https://zhuanlan.zhihu.com/p/411726319

關於錯誤碼的那點事

 

一、什么是錯誤碼

錯誤碼一般情況分為對外錯誤碼,系統內部錯誤碼。

對外錯誤碼常應用在一些開放接口,比如http接口,rpc接口等,通過錯誤碼的形式給予上游更加友好的錯誤提示以及錯誤描述。

系統內部錯誤碼,存在於關系緊密的微服務之間、或者程序的上下游中。因為某種業務錯誤、或者系統不可用造成的錯誤,開發人員可以根據錯誤碼、錯誤信息進行具體定位;或者根據上游根據錯誤碼做業務邏輯判斷,從而保證整體流程完整性。

總而言之,錯誤碼的作用: 指出錯誤的原因,快速定位問題,指導上游系統做出正確的業務判斷,引導用戶進行正確的操作。因此構建一個通用且架構清晰的錯誤碼體系是一件很有必要的事情。

那么怎么定義一種對外對內都友好的錯誤碼呢?至今業內也並沒有一個比較好的方案或者規范。這里結合新老支付系統融合,逐步進行摸索。

二、支付系統錯誤碼現狀

由於歷史原因,公司內部目前有兩套運行中的錢包系統。為了提高錢包系統可用性以及性能,對兩套錢包系統進行遷移整合升級優化。但遷移合並兩套錢包系統的途中,發現兩套錢包系統、以及之前現存的已經優化過的錯誤碼之前存在沖突、類型不一致、定義混亂、隨意性高等問題。

由於其一錢包系統之前由其他團隊開發維護,后期也對其進行重構過,這造成了新錢包系統的錯誤碼定義規則存在兩套;從代碼角度來看,新老錢包系統在設計之初的時候,對錯誤碼的定義都各自定義了一個比較合適的規范,但是在后期開發維護中,越來越少的開發人員去遵循規范定義錯誤碼,最終造成了由錯誤描述決定錯誤碼的現象。而目前新系統中錯誤碼,在設計之初,並未考慮到未來整合帶來的錯誤碼沖突等問題,造成了部分錯誤碼重合,語義大相徑庭的問題,所以重新定義錯誤碼規范也是迫在眉睫。

錢包系統錯誤碼現狀:

錢包一錯誤碼定義: 6位錯誤碼。 首位表示錯誤類型,區分系統級別、校驗、rpc服務調用錯誤。 這種設計方式,第一位是明確的,后面5位都是預留的錯誤碼,長度足夠,滿足后續錯誤碼的增加;缺點錯誤碼對應的類型太少,會出現相同語義的錯誤碼,對應不同的首位數字。后重構版本的錯誤碼修改了原有的錯誤碼位數,修改后7位。造成了該系統的接口層,6位錯誤碼,7位錯誤碼混亂,並且錯誤碼沒有分類,全部順序后排。

錢包二錯誤碼定義: 提供錯誤碼工具類,規定了大多數錢包常用的錯誤碼;然后以此為基礎,進行增加。優點: 錯誤碼分類清晰,結構明了,缺點: 不容易根據錯誤碼定位具體錯誤。

簡單來說,目前錢包系統錯誤碼存在以下問題

1. 錯誤碼字段類型定義不一致。有的定義數值類型,有的定義字符串類型

2.錯誤碼重合問題。相同的錯誤碼,在不同系統中有着不同的語義

三、調研業內接口定義

鑒於當前支付系統錯誤碼的痛點,如錯誤碼應該用數值類型還是字符串類型,長度命名格式是怎樣的等問題,調研了多家大廠的API規范以及接口定義,來探索適用於支付系統的錯誤碼規范。

  1. 微信支付

a. 參考微信支付v2接口

微信支付v2接口: 協議:http, content-type: text/xml

參考鏈接: 

原格式是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.支付寶錯誤碼定義

參考鏈接: 

不同業務的業務錯誤碼: 舉一個接口的例子 

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規范進行歸集: 

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; }
  1. 錯誤碼定義:

構成: 業務+錯誤碼類型+自定義業務編碼; 其中自定義業務編碼是系統自定義的。

標識處理業務 錯誤碼類型(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設計

  1. 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,內部包含錯誤碼定義,以及錯誤的打點上報,錯誤監控大盤等。

發布於 2021-09-24 15:28

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM