接口冪等性的含義
冪等性原本是數(shù)學中的含義稚矿,表達的是N次變換與1次變換的結(jié)果相同捻浦。
而RESTFul API中的冪等性是指調(diào)用某個接口1次或N次桥爽,對所訪問的資源產(chǎn)生的影響結(jié)果都是相同的钠四,需要特別注意的是:這里冪等性指的是對資源產(chǎn)生的影響結(jié)果,而非調(diào)用HTTP請求的返回結(jié)果缀去。
舉個例子,RESTFul API中的GET方法是查詢資源信息褥影,不會對資源產(chǎn)生影響咏雌,所以它是符合冪等性的,但是每次調(diào)用GET方法返回的結(jié)果有可能不同(可能資源的某個屬性在調(diào)用GET方法之前已經(jīng)被其他方法修改了赊抖,例如在多次訪問期間氛雪,接口返回對象的update_time字段被別的請求更新,但GET本身是冪等性的)坛缕。
實際上捆昏,在分布式架構(gòu)中的API冪等性不僅僅針對RESTFul接口毙沾,而是對所有類型的接口適用,目的是為了確保調(diào)用1次或N次接口時對資源的影響結(jié)果都是相同的寇仓。
接口冪等性的好處
接口的冪等性確保了無論調(diào)用1次還是N次對資源的影響都是相同的遍烦,這在某些場合下是非常有用的躺枕。
舉個業(yè)務場景:用戶下單供填,銀行從用戶賬戶扣款罢猪。
有這樣一個接口方法:pay(long account, int money),該方法用于銀行卡扣款支付粘捎,參數(shù)account為賬戶ID危彩,money為需要扣除的錢數(shù)。
當用戶從網(wǎng)頁上點擊支付按鈕時娩缰,在該方法的實現(xiàn)邏輯中需要從指定賬戶中扣除對應的商品價錢泻骤。如果支付操作已經(jīng)成功執(zhí)行,但是響應消息因為某種原因未能及時返回給客戶端演痒,這時候給用戶的體驗是可能是未支付成功趋惨,如果此時再次點擊支付按鈕,那么將再一次執(zhí)行該方法讯嫂,結(jié)果可能會導致用戶只買了一件商品卻扣減了雙份的錢兆沙,這當然是不合理的。整個流程如下圖所示:
當然千扔,就上述例子的場景曲楚,為了避免用戶重復支付褥符,是可以通過別的方式解決的,比如:分布式事務趟大;或者根據(jù)支付狀態(tài)提示給予用戶進行提示等等。
但是护昧,如果引入了分布式事務,那么將帶來實現(xiàn)上的復雜性捣炬,而且會影響到接口性能绽榛;而采取提示信息的方式并不能百分之百確保用戶不會重復支付,存在一定的風險灭美。
而如果接口符合冪等性,即:對同一個訂單無論是執(zhí)行一次支付還是多次支付铁坎,在服務端都確保只會扣一次款犁苏,那么既不需要引入分布式事務的復雜性,也能從根本上解決重復支付的問題围详,這也就是接口符合冪等性的價值所在助赞。
總而言之,接口符合冪等性在可以降低系統(tǒng)實現(xiàn)的復雜性畜普,并能保證資源狀態(tài)的一致性群叶。
HTTP方法的冪等性與安全性
RESTFul風格的接口設(shè)計本質(zhì)上使用的是HTTP協(xié)議的請求方法,因此,RESTFul接口方法的冪等性指的就是HTTP方法的冪等性几晤。
常用的HTTP方法有:
- OPTIONS(獲取服務器信息)
- HEAD(請求資源首部信息)
- GET(獲取資源)
- POST(創(chuàng)建資源)
- PUT(更新資源全部信息)
- PATCH(更新資源部分信息)
- DELETE(刪除資源)
那么植阴,這些HTTP方法的冪等性又是什么樣的呢圾浅?除了冪等性之外狸捕,HTTP方法的安全性是指不對資源產(chǎn)生修改众雷。
如下是常用HTTP方法的冪等性和安全性總結(jié):
HTTP方法名稱 | 是否冪等 | 是否安全 |
---|---|---|
OPTIONS | Y | Y |
HEAD | Y | Y |
GET | Y | Y |
POST | N | N |
PUT | Y | N |
PATCH | N | N |
DELETE | Y | N |
從上述表格中可以看出砾省,HTTP方法的冪等性和安全性并不是同一個概念,如下是對個各個方法的冪等性和安全性解釋:
- OPTIONS方法常常用于獲取服務器信息轩性,不會對資源產(chǎn)生影響狠鸳,也不會對資源進行修改件舵,因此它是冪等的也是安全的;OPTIONS方法最常見的場景是在瀏覽器的跨域請求中蛾派,如果瀏覽器發(fā)起的是一個跨域訪問的API(不論是GET方法還是POST方法)个少,再真正發(fā)送業(yè)務的GET或POST方法之前會發(fā)送一個OPTIONS方法從服務端獲取信息,從服務器返回的信息中得知該請求是否支持跨域訪問壳澳,從而決定下一步是否能成功發(fā)送真正的業(yè)務請求茫经。
- HEAD方法用于請求資源的頭部信息,不會資源產(chǎn)生影響抹镊,也不會對資源進行修改荤傲,因此它是冪等的也是安全的垮耳。
- GET方法用于獲取資源信息,雖然可能每次返回的結(jié)果都不相同,但是GET方法本身不會對資源產(chǎn)生影響终佛,在RESTFul語義里GET方法也不會修改資源俊嗽,因此它是冪等的,也是安全的铃彰。
- POST方法在RESTFul語義里表示新建資源绍豁,顯然調(diào)用1次與調(diào)用N次的結(jié)果不同(調(diào)用1次新建1個資源,調(diào)用N次新建N個資源)牙捉,因此不是冪等的竹揍,同時也不是安全的。
- PUT方法在RESTFul語義里表示對資源進行全量更新鹃共,因此調(diào)用1次或N次的結(jié)果都是一致的鬼佣,所以它是冪等的,但不是安全的霜浴。
- PATCH方法在RESTFul語義里表示對資源的局部更新晶衷,因此不能保證調(diào)用1次與調(diào)用N次的結(jié)果相同(如:被更新的資源某個屬性隨著不同的調(diào)用次數(shù)在變化),所以不是冪等的锹漱,同時也不是安全的哥牍。
- DELETE方法用于刪除資源,調(diào)用1次或N次的結(jié)果都是相同的挠说,因此是冪等的蛙奖,但不是安全的。
如何設(shè)計符合冪等性的接口
設(shè)計冪等性接口的關(guān)鍵在于保證接口不論是被調(diào)用1次還是N次琐脏,它對資源所產(chǎn)生的影響都是相同的。
從上述HTTP方法的冪等性總結(jié)中可以得知掐暮,HTTP協(xié)議的POST和PATCH方法都不是冪等性的(但是我們卻經(jīng)常會在RESTFul接口中使用到它們)路克,那是否就意味中無法將POST和PATCH方法設(shè)計為冪等性接口了呢?答案顯然是否定的灰羽。在上述例子中廉嚼,可以將訂單ID也作為方法參數(shù)之一,如:pay(long account, int money, long order)傍念,這樣在服務端確保一個訂單只會被支付一次(訂單號是全局唯一的),那么無論該方法被調(diào)用1次還是N次結(jié)果都是一樣的秦陋,也就保證了接口的冪等性驳概。當然,在哪些沒有訂單號的場景稚照,可以為接口操作生成一個全局唯一的處理號ID上枕,并把該處理號ID作為方法參數(shù)之一辨萍,這樣在服務端確保一個處理號ID只會被執(zhí)行一次就保證了接口的冪等性锈玉。
符合冪等性的接口調(diào)用流程描述如下圖所示:
寫在最后
雖然說設(shè)計符合冪等性的接口在某些場合可以降低系統(tǒng)的復雜性(如:可以不用引入分布式事務)默终,但是并非在所有場合的問題都能通過冪等性接口解決土陪,在必要的時候依然需要引入分布式事務處理這樣的框架。我們不要也不能把接口冪等性作為萬能的解決辦法源哩,但是励烦,我們在設(shè)計接口時盡量考慮符合冪等性處理是非常有價值的。
【參考】