- 1.post、put、patch:與冪等性
總:
用于上傳數(shù)據(jù)的方法只有POST、PUT、PATCH。
PUT方法和PATCH方法所請(qǐng)求的目標(biāo)地址都是直接指向資源的,而POST方法請(qǐng)求的目標(biāo)是一個(gè)行為處理器。PUT用于替換資源,而PATCH用于更新部分資源。
分:
POST所對(duì)應(yīng)的URI并非創(chuàng)建的資源本身,而是資源的接收者。比如:POST http://www.forum.com/articles 的語(yǔ)義是在http://www.forum.com/articles 下創(chuàng)建一篇帖子,HTTP響應(yīng)中應(yīng)包含帖子的創(chuàng)建狀態(tài)以及帖子的URI。兩次相同的POST請(qǐng)求會(huì)在服務(wù)器端創(chuàng)建兩份資源,它們具有不同的URI;所以,POST方法不具備冪等性。
而PUT所對(duì)應(yīng)的URI是要?jiǎng)?chuàng)建或更新的資源本身。比如:PUT http://www.forum/articles/4231 的語(yǔ)義是創(chuàng)建或更新ID為4231的帖子。對(duì)同一URI進(jìn)行多次PUT的副作用和一次PUT是相同的;因此,PUT方法有冪等性。
POST方法非冪等可以理解,因?yàn)樗?qǐng)求服務(wù)器執(zhí)行一個(gè)動(dòng)作,多次發(fā)起請(qǐng)求可能導(dǎo)致動(dòng)作多次執(zhí)行。
而像PATCH這樣請(qǐng)求的目標(biāo)是一個(gè)資源的,PATCH方法和POST方法有個(gè)很相似的地方,它們的實(shí)體部分都是結(jié)構(gòu)化的數(shù)據(jù)。POST方法的實(shí)體結(jié)構(gòu)一般是 multipart/form-data 或 application/x-www-form-urlencoded 而PATCH方法的實(shí)體結(jié)構(gòu)則隨其它規(guī)范定義。
這和PUT方法的無(wú)結(jié)構(gòu)實(shí)體相比就是最大的區(qū)別?! UT方法的實(shí)體無(wú)結(jié)構(gòu)的,它直接把實(shí)體部分的數(shù)據(jù)替換到服務(wù)器的資源上。f而PATCH提供的實(shí)體則需要根據(jù)程序或其它協(xié)議的定義,解析后在服務(wù)器上執(zhí)行,以此來(lái)修改服務(wù)器上的數(shù)據(jù)。也就是說(shuō),PATCH請(qǐng)求是會(huì)執(zhí)行某個(gè)程序的,如果重復(fù)提交,程序可能執(zhí)行多次,對(duì)服務(wù)器上的資源就可能造成額外的影響,這就可以解釋它為什么是不冪等的了。
- 2.為什么需要冪等性呢?我們先從一個(gè)例子說(shuō)起,假設(shè)有一個(gè)從賬戶(hù)取錢(qián)的遠(yuǎn)程API(可以是HTTP的,也可以不是),我們暫時(shí)用類(lèi)函數(shù)的方式記為:
bool withdraw(account_id, amount)
withdraw的語(yǔ)義是從account_id對(duì)應(yīng)的賬戶(hù)中扣除amount數(shù)額的錢(qián);如果扣除成功則返回true,賬戶(hù)余額減少amount;如果扣除失敗則返回false,賬戶(hù)余額不變。值得注意的是:和本地環(huán)境相比,我們不能輕易假設(shè)分布式環(huán)境的可靠性。一種典型的情況是withdraw請(qǐng)求已經(jīng)被服務(wù)器端正確處理,但服務(wù)器端的返回結(jié)果由于網(wǎng)絡(luò)等原因被掉丟了,導(dǎo)致客戶(hù)端無(wú)法得知處理結(jié)果。如果是在網(wǎng)頁(yè)上,一些不恰當(dāng)?shù)脑O(shè)計(jì)可能會(huì)使用戶(hù)認(rèn)為上一次操作失敗了,然后刷新頁(yè)面,這就導(dǎo)致了withdraw被調(diào)用兩次,賬戶(hù)也被多扣了一次錢(qián)。
另一種更輕量級(jí)的解決方案是冪等設(shè)計(jì)。我們可以通過(guò)一些技巧把withdraw變成冪等的,比如:
int create_ticket() bool idempotent_withdraw(ticket_id, account_id, amount)
create_ticket的語(yǔ)義是獲取一個(gè)服務(wù)器端生成的唯一的處理號(hào)ticket_id,它將用于標(biāo)識(shí)后續(xù)的操作。idempotent_withdraw和withdraw的區(qū)別在于關(guān)聯(lián)了一個(gè)ticket_id,一個(gè)ticket_id表示的操作至多只會(huì)被處理一次,每次調(diào)用都將返回第一次調(diào)用時(shí)的處理結(jié)果。這樣,idempotent_withdraw就符合冪等性了,客戶(hù)端就可以放心地多次調(diào)用。
基于冪等性的解決方案中一個(gè)完整的取錢(qián)流程被分解成了兩個(gè)步驟:1.調(diào)用create_ticket()獲取ticket_id;2.調(diào)用idempotent_withdraw(ticket_id, account_id, amount)。雖然create_ticket不是冪等的,但在這種設(shè)計(jì)下,它對(duì)系統(tǒng)狀態(tài)的影響可以忽略,加上idempotent_withdraw是冪等的,所以任何一步由于網(wǎng)絡(luò)等原因失敗或超時(shí),客戶(hù)端都可以重試,直到獲得結(jié)果。如圖2所示:

- 3.說(shuō)一下get 、delete:
HTTP GET方法用于獲取資源,不應(yīng)有副作用,所以是冪等的。比如:GET http://www.bank.com/account/123456 ,不會(huì)改變資源的狀態(tài),不論調(diào)用一次還是N次都沒(méi)有副作用。請(qǐng)注意,這里強(qiáng)調(diào)的是一次和N次具有相同的副作用,而不是每次GET的結(jié)果相同。GET http://www.news.com/latest-news 這個(gè)HTTP請(qǐng)求可能會(huì)每次得到不同的結(jié)果,但它本身并沒(méi)有產(chǎn)生任何副作用,因而是滿(mǎn)足冪等性的。
HTTP DELETE方法用于刪除資源,有副作用,但它應(yīng)該滿(mǎn)足冪等性。比如:DELETE http://www.forum.com/article/4231 ,調(diào)用一次和N次對(duì)系統(tǒng)產(chǎn)生的副作用是相同的,即刪掉id為4231的帖子;因此,調(diào)用者可以多次調(diào)用或刷新頁(yè)面而不必?fù)?dān)心引起錯(cuò)誤。
- 4.說(shuō)一下post 和 get的區(qū)別?