本文主要以HTTP GET、DELETE、PUT、POST四種方法為主進(jìn)行語義和冪等性的介紹。
HTTP GET方法用于獲取資源,不應(yīng)有副作用,所以是冪等的。比如:GET http://www.bank.com/account/123456,不會改變資源的狀態(tài),不論調(diào)用一次還是N次都沒有副作用。請注意,這里強(qiáng)調(diào)的是一次和N次具有相同的副作用,而不是每次GET的結(jié)果相同。GET http://www.news.com/latest-news這個HTTP請求可能會每次得到不同的結(jié)果,但它本身并沒有產(chǎn)生任何副作用,因而是滿足冪等性的。
HTTP DELETE方法用于刪除資源,有副作用,但它應(yīng)該滿足冪等性。比如:DELETE http://www.forum.com/article/4231,調(diào)用一次和N次對系統(tǒng)產(chǎn)生的副作用是相同的,即刪掉id為4231的帖子;因此,調(diào)用者可以多次調(diào)用或刷新頁面而不必?fù)?dān)心引起錯誤。
HTTP POST方法用于創(chuàng)建資源,所對應(yīng)的URI并非創(chuàng)建的資源本身,而是去執(zhí)行創(chuàng)建動作的操作者,有副作用,不滿足冪等性。比如:POST http://www.forum.com/articles的語義是在http://www.forum.com/articles下創(chuàng)建一篇帖子,HTTP響應(yīng)中應(yīng)包含帖子的創(chuàng)建狀態(tài)以及帖子的URI。兩次相同的POST請求會在服務(wù)器端創(chuàng)建兩份資源,它們具有不同的URI;所以,POST方法不具備冪等性。
HTTP PUT方法用于創(chuàng)建或更新操作,所對應(yīng)的URI是要創(chuàng)建或更新的資源本身,有副作用,它應(yīng)該滿足冪等性。比如:PUT http://www.forum/articles/4231的語義是創(chuàng)建或更新ID為4231的帖子。對同一URI進(jìn)行多次PUT的副作用和一次PUT是相同的;因此,PUT方法具有冪等性。
利用Web API的形式實現(xiàn)前面所提到的取款功能。
1、用POST /tickets來實現(xiàn)create_ticket;
2、用PUT /accounts/account_id/ticket_id&amount=xxx來實現(xiàn)idempotent_withdraw。
值得注意的是嚴(yán)格來講amount參數(shù)不應(yīng)該作為URI的一部分,真正的URI應(yīng)該是/accounts/account_id/ticket_id,而amount應(yīng)該放在請求的body中。這種模式可以應(yīng)用于很多場合,比如:論壇網(wǎng)站中防止意外的重復(fù)發(fā)帖。
電商中遇到的問題
如何防范 POST 重復(fù)提交
HTTP POST 操作既不是安全的,也不是冪等的(至少在HTTP規(guī)范里沒有保證)。當(dāng)我們因為反復(fù)刷新瀏覽器導(dǎo)致多次提交表單,多次發(fā)出同樣的POST請求,導(dǎo)致遠(yuǎn)端服務(wù)器重復(fù)創(chuàng)建出了資源。
所以,對于電商應(yīng)用來說,第一對應(yīng)的后端 WebService 一定要做到冪等性,第二服務(wù)器端收到 POST 請求,在操作成功后必須302跳轉(zhuǎn)到另外一個頁面,這樣即使用戶刷新頁面,也不會重復(fù)提交表單。
使用客戶端JS腳本
使用session?
<form id = "form" method ="post">
<input type="hidden" name="token" value="xxx">
</form>
當(dāng)以后請求
把分布式事務(wù)分解為具有冪等性的異步消息處理
電商的很多業(yè)務(wù),考慮更多的是 BASE(即Basically Available、Soft state、和Eventually consistent),而不是 ACID(Atomicity、Consistency、Isolation和 Durability)。即為了滿足高負(fù)載的用戶訪問,我們可以容忍短暫的數(shù)據(jù)不一致。那怎么做呢?
第一,不做分布式事務(wù),代價太大。
第二,不一定需要實時一致性,只需要保證最終的一致性即可。
第三,“通過狀態(tài)機(jī)和嚴(yán)格的有序操作,來最大限度地降低不一致性”。
第四,最終一致性(Eventually Consistent)通過異步事件做到。
如果消息具有操作冪等性,也就是一個消息被應(yīng)用多次與應(yīng)用一次產(chǎn)生的效果是一樣的話,那么把不需要同步執(zhí)行的事務(wù)交給異步消息推送和訂閱者集群來處理即可。假如消息處理失敗,那么就消息重播,由于冪等性,應(yīng)用多次也能產(chǎn)生正確的結(jié)果。
實際情況下,消息很難具有冪等性,解決方法是使用另一個表記錄已經(jīng)被成功應(yīng)用的消息,即消息隊列和消息應(yīng)用狀態(tài)表一起來解決問題。