細說RESTful API之冪等性

目錄

接口冪等性的含義

冪等性本來是數學中的含義,表達式的是N次變換與1次變換的結果相同。
而RESTFul API中的冪等性是指調用某個方法1次或N次對資源產生的影響結果都是相同的,須要特別注意的是:這裏冪等性指的是對資源產生的影響結果,而不是調用HTTP方法的返回結果。
舉個例子,RESTFul API中的GET方法是查詢資源信息,不會對資源產生影響,因此它是符合冪等性的,可是每次調用GET方法返回的結果有可能不一樣(可能資源的某個屬性在調用GET方法以前已經被其餘方法修改了)。
實際上,在分佈式架構中的API冪等性不只僅針對RESTFul接口,而是對全部類型的接口適用,目的是爲了確保調用1次或N次接口時對資源的影響結果都是相同的。html

接口符合冪等性有什麼用處

接口的冪等性確保了不管調用1次仍是N次對資源的影響都是相同的,這在某些場合下是很是有用的。
舉個例子,有這樣一個接口方法:pay(long account, int money),該方法用於銀行卡扣款支付,參數account爲帳戶ID,money爲須要扣除的錢數。當用戶從網頁上點擊支付按鈕時,在該方法的實現邏輯中須要從指定帳戶中扣除對應的商品價錢。若是支付操做已經成功執行,可是響應消息由於某種緣由未能及時返回給客戶端,這時候給用戶的體驗是多是未支付成功,若是此時再次點擊支付按鈕,那麼將再一次執行該方法,結果可能會致使用戶只買了一件商品卻花了雙份的錢,這固然是不合理的。整個流程以下圖所示:
接口不符合冪等性git

固然,就上述例子的場景,爲了不用戶重複支付,是能夠經過別的方式解決的,好比:分佈式事務,或者根據支付狀態提示給予用戶進行提示等等。
可是,若是引入了分佈式事務,那麼將帶來實現上的複雜性,並且會影響到接口性能;而採起提示信息的方式並不能百分之百確保用戶不會重複支付,存在必定的風險。而若是接口符合冪等性,即:對同一個訂單不管是執行一次支付仍是屢次支付,在服務端都確保只會扣一次款,那麼既不須要引入分佈式事務的複雜性,也能從根本上解決重複支付的問題,這也就是接口符合冪等性的價值所在。github

總而言之,接口符合冪等性在能夠下降系統實現的複雜性,並能保證資源狀態的一致性。跨域

HTTP方法的冪等性與安全性

RESTFul風格的接口設計本質上使用的是HTTP協議方法,所以,RESTFul接口方法的冪等性指的就是HTTP方法的冪等性。
經常使用的HTTP方法有:OPTIONS(獲取服務器信息),HEAD(請求資源首部信息),GET(獲取資源),POST(建立資源),PUT(更新資源所有信息),PATCH(更新資源部分信息),DELETE(刪除資源)。那麼,這些HTTP方法的冪等性又是什麼樣的呢?
除了冪等性以外,HTTP方法的安全性是指不對資源產生修改。
以下是經常使用HTTP方法的冪等性和安全性總結:瀏覽器

HTTP方法名稱 是否冪等 是否安全
OPTIONS Y Y
HEAD Y Y
GET Y Y
PUT Y N
DELETE Y N
POST N N
PATCH N N

從上述表格中能夠看出,HTTP方法的冪等性和安全性並非同一個概念,以下是對個各個方法的冪等性和安全性解釋:安全

  • OPTIONS方法經常用於獲取服務器信息,不會對資源產生影響,也不會對資源進行修改,所以它是冪等的也是安全的;OPTIONS方法最多見的場景是在瀏覽器的跨域請求中,若是瀏覽器發起的是一個跨域訪問的API(不管是GET方法仍是POST方法),再真正發送業務的GET或POST方法以前會發送一個OPTIONS方法從服務端獲取信息,從服務器返回的信息中得知該請求是否支持跨域訪問,從而決定下一步是否能成功發送真正的業務請求。
  • HEAD方法用於請求資源的頭部信息,不會資源產生影響,也不會對資源進行修改,所以它是冪等的也是安全的。
  • GET方法用於獲取資源信息,雖然可能每次返回的結果都不相同,可是GET方法自己不會對資源產生影響,在RESTFul語義裏GET方法也不會修改資源,所以它是冪等的,也是安全的。
  • PUT方法在RESTFul語義裏表示對資源進行全量更新,所以調用1次或N次的結果都是一致的,因此它是冪等的,但不是安全的。
  • DELETE方法用於刪除資源,調用1次或N次的結果都是相同的,所以是冪等的,但不是安全的。
  • POST方法在RESTFul語義裏表示新建資源,顯然調用1次與調用N次的結果不一樣(調用1次新建1個資源,調用N次新建N個資源),所以不是冪等的,同時也不是安全的。
  • PATCH方法在RESTFul語義裏表示對資源的局部更新,所以不能保證調用1次與調用N次的結果相同(如:被更新的資源某個屬性隨着不一樣的調用次數在變化),因此不是冪等的,同時也不是安全的。

如何設計符合冪等性的接口

設計冪等性接口的關鍵在於保證接口不管是被調用1次仍是N次,它對資源所產生的影響都是相同的。
從上述HTTP方法的冪等性總結中能夠得知,HTTP協議的POST和PATCH方法都不是冪等性的(可是咱們卻常常會在RESTFul接口中使用到它們),那是否就意味中沒法將POST和PATCH方法設計爲冪等性接口了呢?答案顯然是否認的。在上述例子中,能夠將訂單ID也做爲方法參數之一,如:pay(long account, int money, long order),這樣在服務端確保一個訂單隻會被支付一次(訂單號是全局惟一的),那麼不管該方法被調用1次仍是N次結果都是同樣的,也就保證了接口的冪等性。固然,在哪些沒有訂單號的場景,能夠爲接口操做生成一個全局惟一的處理號ID,並把該處理號ID做爲方法參數之一,這樣在服務端確保一個處理號ID只會被執行一次就保證了接口的冪等性。
符合冪等性的接口調用流程描述以下圖所示:
接口符合冪等性服務器

寫在最後

雖說設計符合冪等性的接口在某些場合能夠下降系統的複雜性(如:能夠不用引入分佈式事務),可是並不是在全部場合的問題都能經過冪等性接口解決,在必要的時候依然須要引入分佈式事務處理這樣的框架。咱們不要也不能把接口冪等性做爲萬能的解決辦法,可是,咱們在設計接口時儘可能考慮符合冪等性處理是很是有價值的。restful

【參考】
http://blog.720ui.com/2016/restful_idempotent/ 如何理解RESTful的冪等性
https://www.cnblogs.com/weidagang2046/archive/2011/06/04/idempotence.html 理解HTTP冪等性
https://sofish.github.io/restcookbook/http%20methods/idempotency/ RESTful 手冊架構

相關文章
相關標籤/搜索