針對【API介面通訊引數規範】這篇文章留下的幾個問題進行探討。
問題1
試想一下,如果一個http請求返回一個500給我們,那我們是不是都不用看詳情都知道該次請求發生了什麼?這正是一個標準的結果碼意義所在。在公司所有的系統中,API遵循同一套結果碼,那這樣同事A在呼叫同事B的介面時,對於返回的結果碼是非常具有可讀性的,我們不用面對面交流都知道返回的結果是一個什麼樣的情況。
XML方案
在此先給出上一篇文章針對Result的另一個方案,是基於XML來定義結果碼的,可能有些公司喜歡XML這種配置檔案,因為可以不用重新發布應用程式(其實大多數情況下還是需要重新發布的,後面會講解)。這裡面的主要變化是我們不再從列舉ResultCode中獲取提示資訊,這些提示資訊會放在XML上,看看我們的Result中的Message屬性的變化
/// <summary> /// 結果訊息 /// </summary> public string Message { get { return _message ?? XmlResultCodeHelper.GetResultMsg((int)Code); } set { _message = value; } }
看看我們的這個幫助類
/// <summary> /// xml結果碼幫助類 /// </summary> public class XmlResultCodeHelper { private static List<XmlResultCode> xmlResultCode = new List<XmlResultCode>(); //獲取xml裡面對應的msg public static string GetResultMsg(int key) { if (xmlResultCode.Count==0) { dynamic type = (new ErrorCodes()).GetType(); string currentDirectory = Path.GetDirectoryName(type.Assembly.Location); string path = currentDirectory + "\\XmlResultCodes.xml"; xmlResultCode= path.XmlDeserializeFromFile<List<XmlResultCode>>(); } var code = xmlResultCode.FirstOrDefault(q => q.Code == key); if(null == code) throw new InvalidOperationException("沒有配置對應的xml節點"); return code.Msg; } } /// <summary> /// xml結果碼 /// </summary> public class XmlResultCode { public int Code { get; set; } public string Msg { get; set; } }
這個類主要是幫助我們獲取到XmlResultCodes.xml並且返回裡面對應的msg,這方法裡面的xml反序列方法我就不再貼出來了,大家百度一下即可。
看一下我們的XmlResultCodes.xml,這裡看得出是一個鍵值對
<?xml version="1.0" encoding="utf-8"?> <ArrayOfErrorCode xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <ErrorCode> <Code>1</Code> <Msg>操作成功</Msg> </ErrorCode> <ErrorCode> <Code>10</Code> <Msg>操作失敗</Msg> </ErrorCode> <ErrorCode> <Code>11</Code> <Msg>登陸失敗</Msg> </ErrorCode> <ErrorCode> <Code>13</Code> <Msg>引數不正確</Msg> </ErrorCode> <ErrorCode> <Code>20</Code> <Msg>使用者不存在</Msg> </ErrorCode> <ErrorCode> <Code>21</Code> <Msg>沒有資料</Msg> </ErrorCode> </ArrayOfErrorCode>
再看看我們這個ResultCode列舉,對比上篇文章,已經不需要DisplayAttribute了
public enum ResultCode { /// <summary> /// 操作成功 ///</summary> Ok = 1, /// <summary> /// 操作失敗 ///</summary> Fail = 10, /// <summary> /// 登陸失敗 ///</summary> LoginFail = 11, /// <summary> /// 引數不正確 ///</summary> InvalidParams = 13, /// <summary> /// 使用者不存在 ///</summary> NoSuchUser = 20, /// <summary> /// 沒有該資料 ///</summary> NoRecord = 21, }
那這種情況ResultCode對我們的意義是什麼呢?且看下面例子
//情況1 return Result.FromCode(13); //情況2 return Result.FromCode(ResultCode.InvalidParams);
我們雖然英文口語不一定流利:),但是憑藉我們的睿智,肯定會讓我們選擇情況2使程式具有更高的可讀性,不然新人接手專案,吐槽是少不了的,難保自己過了段時間再看這樣的設計,這返回的13是什麼鬼?
OK,XML的方案基本可以了,總結一下步驟:
1. 在ResultCode中定義好自己的英文(使程式具有更高的可讀性)和對應列舉的數值
2. 在XmlResultCodes.xml中定義這個數值對應的提示資訊
同樣我們也會審視這個設計方案的問題所在:為什麼會採用XML?就是衝著不用重新發布嘛。是的,改提示資訊是可以不用重新發布,但是在xml裡面新增了新的節點呢?新增了之後我們得用啊,一樣要在業務中呼叫這個新的節點,還不是一樣要重新發布?這樣看來我們基於這個XML的設計方案並沒有完全達到我們的初衷的。
怎麼辦?且看下面的問題。
問題2
我們如何做到統一呢?中心式的管理,在管理後臺中,把所有的結果碼和對應的訊息都寫入資料庫,然後通過Redis載入作為快取,在獲取提示資訊的時候訪問Redis返回我們需要的資訊。
public class ResultCodeHelper { public static string GetResultMsg(int key) { //從redis資料庫根據key獲取到value } }
這裡只是虛擬碼,大家根據自己的Redis的熟知情況設計方案。
現在這個ResultCode的增刪改都只能讓管理員在管理後臺操作了,開發人員最好是有許可權能檢視到ResultCode的所有結果碼和資訊,這樣在新增之前才能知道是否存在類似的結果碼進而避免重複。修改和刪除結果碼?最好不要,你有見過Http狀態碼的更改嗎?這種公司級別的通訊規範,作為基礎設施架構就最好先設計和定義,後續專案多起來,都可以有據可依。
來看一下我們結果碼定義和使用的流程:
1. ResultCode在管理後臺的定義和儲存
2. 載入到Redis並獲取對應值的資訊
3. 每個專案都定義好自己的ResultCode對應的列舉和值(使程式具有更高的可讀性)
至此我們通過DisplayAttribute和XML獲取提示資訊這兩種方案都已經被分散式快取Redis方案代替了,我們做了那麼多,並且耦合了Redis快取,這樣做究竟有什麼好處呢?就像我們的標題闡述的主題一樣,規範!規範會讓後續的專案管理花費更少的effor。
讓我知道如果你有更好的想法!