API接口設計要考慮的幾個重要原則和方法總結

轉載:https://ask.zkbhj.com/?/article/254

這裏想和大家討論的是在後臺接口設計過程中,還有哪些方面需要考慮,以及還有哪些優秀的技術實踐方案可以借鑑。

 【規範和最佳實踐】

1.合理的接口命名;

接口的命名必須規範優雅,在未看到接口文檔時,就可以根據接口的URL明白接口的功能是什麼?

如下面的例子:







//好的接口命名示例
/customer/cert/search.json

//不好的接口命名示例
/customer/info/get.json


2.入參和出參的規範化定義,有統一的風格;

一個項目內的所有接口,必須有統一的風格,統一返回格式,約定業務層錯誤編碼,每個編碼可以攜帶明確的錯誤信息。出入參字段含義明確,採用統一的命名規範,如駝峯命名等。返回格式統一採用json格式。舉一個例子:


{
    "status": "failure",
    "error_code": 100003,
    "error_message": "未獲取到用戶信息",
    "data": 
}

status標識接口是否邏輯處理成功;error_code爲不同類型錯誤信息對應的唯一錯誤碼,error_message爲錯誤信息的簡要描述信息(注意某些數據或者信息是否可直接展示給用戶),data則爲需要返回給調用方的數據信息。
 
另外,每個參數一定要有明確且固定的數據格式,int就是int,string就是string,array就是array,object就是object,因爲對於一些對數據類型要求比較嚴格的使用方,不明確的數據格式返回,可能會造成不可預知的錯誤。
 
下面給大家列一下Json裏的六種基本數據格式: 




Number:整數或浮點數
String:字符串
Boolean:true 或 false
Array:數組包含在方括號中
Object:對象包含在大括號{}中
Null:空類型






 
3.接口的功能定義要具備單一性;

單一性是指接口要做的事情應該是一個比較單一的事情,比如登陸接口,登陸完成應該只是返回登陸成功以後一些用戶信息如uid即可,但很多人爲了減少接口交互,返回一大堆額外的數據。

但有時候對於一些內部系統接口來講,爲了實現通用性,可能會提供一些通用的查詢接口,即在同一個接口內返回儘可能多的信息,但也不建議這麼做,至少不是一個好的實踐;


4.明確接口支持的協議;

接口要明確所支持的協議,是POST/GET/PUT/DELETE等的哪一個。一般來講,同一個接口而言,儘量只支持一種協議,並且在接口被調用時,如果參數傳遞非接口定義協議,要明確提示返回錯誤信息,這樣可以減少很多類似於“爲啥我調接口參數都對還調不通”的問題的溝通成本。同時,嚴格的協議規範也可以避免一些意料之外的問題出現。例如:










您請求的資源不支持 http 方法“POST


5.是否支持冪等;

這是作爲一個接口而言,很需要明確的一點,尤其是在一些特殊的應用場景下,是否支持冪等是需要首先明確的。比如下面這個例子:

發放卡券的接口:/coupon/card/handOut.json POST

這是一個卡券系統裏發放租金卡的接口,支持POST協議傳參。由於很多種原因,同一類卡券被某個人領取時,都可能會產生接口被調用不支持一次的情形,比如網絡抖動、用戶快速點擊、甚至是惡意刷接口等,我們希望,對於“同一個調用”,我們給用戶返回的結果應該是一致的,這就是冪等。實現冪等的方式有幾種,比如卡券系統就是通過生成訂單號的形式完成的接口冪等;


6、充分考慮接口的可擴展性,避免做大而全的接口;

要根據實際業務場景定義接口,充分考慮接口的可擴展性。比如自如的APP首頁數據接口,我們可以設計成整個首頁就一個大接口,但是假如這樣,未來再次改版APP,我們可能就需要完全重新寫這個接口,但假如我們按模塊區分接口,可能我們僅需要開發新增加的模塊的接口,對於以前有的,在數據結構不調整隻做樣式改變的需求裏,就可以減少工作量的開發。
另外這麼做還有一個優點,尤其對移動端作用尤爲突出,由於移動端對帶寬有限,所以,接口中儘量不要返回無用的信息,只返回真正需要的數據,進而減少由於過多的數據量影響處理速度,最重要的是影響傳輸效率。


7、接口裏儘量不做客戶端可以處理的邏輯,減少服務端壓力;

接口主要是提供給客戶端數據的,對於能夠在客端完成的邏輯處理,儘量由客端來處理(當然APP比較特殊,如果改動這部分邏輯需要發版,還是需要放在後端),進而減輕後端服務器的壓力,讓後端接口更加“專心”做好數據服務;


8、清晰的日誌分類、記錄以及歸檔規範;

接口日誌很重要,無論對於追溯問題還是解決bug,都有着舉足輕重的作用。所以,好的日誌規範,是一個很好的習慣。日誌主要有info和error兩種(warning一般不做記錄,或者很少用到),info日誌一般用於記錄現場,用來追溯問題;error日誌一般用於協作我們查找bug,定位代碼問題。

另外日誌也需要定期做歸檔處理,防止機器磁盤被日誌文件大量佔用。

更高級的,可以接入一些日誌蒐集和分析工具,如ELK等,將日誌信息持久化存儲以及可視化展示,更加方便的對日誌信息進行使用。


9、版本控制:
 
這一點,對於接口來講,非常重要。在實際的場景中,維護多個版本是非常常見的事情,在系統的迭代升級過程中,無可避免的會增減返回參數及入參,修改返回數據的結構,甚至會廢棄原有接口改爲新的數據接口。所以,爲了不影響老版本應用的正常使用,大部分應用後臺都會針對性的維護多個接口版本。
一般來講,有2中常用的方式:

































1.每個接口有各自的版本,一般爲接口添加個version的參數。 
2.整個接口系統有統一的版本,一般在URL中添加版本號,比如 http://api.zkbhj.com/v2。 


 

【性能和高可用】

1、接口的平均響應時長、支持的併發數、TPS;

這個很重要,無論是我們自己設計的接口,還是我們在使用第三方提供的接口時,我們都需要明確接口的平均響應時長,因爲這直接關係到你係統的安全性問題!如果在接口調用時,沒有設置合理的超時時間甚至都沒有設置超時時間,那麼一旦所以依賴的接口出現問題甚至服務不可用時,對你調用方系統來講,將是致命的,雪崩式的系統崩潰,很大一部分就是由於這個原因造成的。所以爲了不害人害己,設計以及最終提供的接口,一定要提供一個明確的接口平均響應時長,而且要在接口文檔中寫明並強烈建議接口調用方設置合理的超時時間,防止由於接口超時而造成雪崩式的連鎖反應。


2、數據庫和緩存的選擇;

爲了提高接口性能,合理的選擇數據庫和緩存很是總要。一般情況下,關係型存儲我們一般都會選擇MySQL數據庫,緩存一般都選擇Redis。當然,MySQL數據庫的分庫分表,加索引用事務、讀寫分離等,redis作爲緩存使用時的緩存時長、緩存數據類型等,都有他們的使用原則和最佳實踐,這裏不做贅述。我們這裏只討論在何種場景下要使用緩存。比如查詢類型的接口,如果要查詢的數據並不是實時性要求很高的接口,那我們可以進行緩存處理,比如APP首頁接口,一般都是CMS裏面配置的一些圖文信息,我們有必要做緩存處理。當然可能裏面有一部分數據是需要實時的,比如自如寓的管家信息,那我們可以把這一部分內容做實時的處理。
 

3、限流、熔斷和降級;

對於一些特殊的應用場景,比如搶紅包、秒殺等,要對接口進行限流處理,方式短時間內的高併發請求將接口搞死;

接口熔斷和降級,是爲了解決系統不被拖死,不影響核心業務流程而採取的措施,比如獲取用戶信息列表,實時獲取用戶頭像和暱稱的接口暫時不可用(比如根據設置,10個請求裏6個以上都超時,則判定爲服務不可用,觸發熔斷機制),我們可以主動放棄調用(熔斷),只返回核心數據uid等,暱稱和頭像暫時返回默認數據(降級);


4、消除單點,負載均衡;

對於任何一個接口服務,我們至少要有2臺機器對外提供服務,禁止單點服務,單點一旦出問題,會直接造成服務不可用;

對於訪問量很大的API服務,爲了提供更加快速的接口響應,我們往往不是單臺機器提供服務,而是有多臺機器組成一個分佈式集羣對外提供服務。這個時候就會涉及到負載均衡,比如我們就會由nginx來做負載均衡,根據一定的策略機制,將接口請求平均的分發到不同的應用機器上進行處理和響應。進而提高接口的性能。


5、是否有第三方服務接口?

如果接口依賴了第三方服務接口,能用緩存就用緩存。這樣可以進一步降低由於第三方接口不穩定給我們自己系統造成的波動。當然,也有一些第三方接口無法做緩存,比如就是要實時進行身份驗證等,這個時候,超時時間的設置就尤爲重要!


6、能異步處理的異步處理:

其實有很多場景下,一個接口裏面的很多邏輯是可以異步處理的。舉個例子:

比如用戶註冊場景,用戶註冊成功之後會給客戶的郵箱發送一封激活郵件。常規的邏輯流程應該是,前段提交用戶信息到註冊接口,註冊接口做各種校驗,校驗通過後,發送郵件,發送成功後,返回給前端告訴用戶註冊成功,請進入郵箱激活賬號。其實,這個流程裏的“發送郵件”就是可以拿出來異步處理的部分,當校驗通過而且註冊完成之後,我們把發送郵件這件事拋出去,交給另外一個就負責發郵件的任務進行處理(如我們現在有的補償隊列,或者是發一個MQ消息),然後直接返回給用戶註冊成功。這樣,註冊接口的平均響應時間一定會比第一種方案提高很多。


7、更高要求的高可用,可以採用異地機房部署;

在物理地域上就分開部署,兩地同時崩潰的概率還是比較低的;


8、監控和報警;

在對接口建立高效的監控和報警機制,能夠及時發現問題並通知到相應的人員進行第一時間的處理和跟進。


【穩定和安全】

1、身份驗證;

在一些接口場景中,是要依賴於用戶身份的,比如通過token還實現用戶身份的驗證;


2、接口防抓取和串改數據;

防止數據被輕易抓取到,我們可以採用https作爲接口的網絡傳輸協議,進而保證數據包不被輕易的就抓取和分析。即使這種情況下,依然被抓取到,我們還可以對傳輸的數據進行我們自己的加密處理,比如用對稱加密算法AES或者非對稱加密算法RSA,亦或是我們系統內部自己商定好的加密算法,對數據進行加密處理,這樣,即使抓取到數據包,也很難分析出數據的原始信息。

對於防止數據被串改,可以使用sign驗籤,進一步防止接口參數被串改的可能性。


3、防刷;

接口防刷會有一些策略,根據實際的應用場景進行選擇,比如增加圖形驗證碼、接入智能驗證碼、時間戳限制單位時間內的調用次數、ip限制等;

另外監控很重要,及時發現異常的調用,進行封禁處理;


【其他】

1、是否需要支持跨域;

這一點是針對於H5提供接口時需要考慮的,因爲一般情況下,實際的應用和接口所在的域並不是同一個域,基於瀏覽器的安全策略,對於XHR請求來講,是不允許進行跨域請求的,所以,一般提供給H5的接口要支持跨域請求。當然解決跨域的方法也不在本次討論的範圍之內,目前主流的方式就是在服務器配置的header頭信息中增加兩項參數。



2、基於H5提供接口的一些安全性問題;

比如常見的CSRF攻擊,我們可以在接口裏驗證 HTTP Referer字段、x-requested-with字段、header中增加token等,從一定程度上提高被CSRF攻擊的門檻。 
 
3、在代碼結構層面,儘量和其他部分分開;
 
API集中由同一個系統“模塊”提供,儘量不要和頁面等其他功能混合開發。例如下面的項目分層模式就是一個較好的實踐方案:
 






















































































QQ截圖20181112160646.jpg


 
即所有API接口均分佈在api內部,不與pc(PC站頁面)、mobile(M站頁面)等混合在一起。 

4、文檔:
 
好的接口,還有一項優點,就是會有爲之配套的接口文檔。如果希望降低接口文檔的維護成本等,也可以使用開源的第三方自動化接口文檔工具,比如swagger等。





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章