HTTP Method 詳細解讀(`GET` `HEAD` `POST` `OPTIONS` `PUT` `DELETE` `TRACE` `CONNECT`)--轉

前言

HTTP Method的歷史:html

  1. HTTP 0.9 這個版本只有GET方法
  2. HTTP 1.0 這個版本有GET HEAD POST這三個方法
  3. HTTP 1.1 這個版本是當前版本,包含GET HEAD POST OPTIONS PUT DELETE TRACE CONNECT這8個方法

咱們先看看HTTP 1.1 規範的中文翻譯數據庫

方法定義(Method Definitions)

HTTP/1.1經常使用方法的定義以下。雖然方法能夠被展開,但新加的方法不能認爲能分享與擴展的客戶端和服務器一樣的語義。瀏覽器

Hst請求頭域(見13.23節)必須能在全部的HTTP/1.1請求裏出現。緩存

9.1 安全和等冪(Idempotent)方法

9.1.1安全方法(Safe Methods)

實現者應當知道軟件是表明用戶在互聯網上進行交互,而且應該當心地容許用戶知道任何它們可能採起的動做(action),這些動做可能給他們本身或他人帶來沒法預料的結果。安全

特別的,GET和HEAD方法僅僅應該獲取資源而不是執行動做(action)。這些方法應該被考慮是「安全」的。可讓用戶代理用其餘的方法,如:POST,PUT,DELETE,這樣用戶代理就能知道這些方法可能會執行不安全的動做。服務器

天然的,保證當服務器因爲執行GET請求而不能產生反作用是不可能的;實際上,一些動態的資源會考慮這個特性。用戶並無請求這些反作用,所以不須要對這些反作用負責。網絡

9.1.2等冪方法(Idempotent Mehtods)

方法能夠有等冪的性質由於(除了出錯或終止問題)N>0個相同請求的反作用同單個請求的反作用的效果是同樣(譯註:等冪就是值不變性,相同的請求獲得相同的響應結果,不會出現相同的請求出現不一樣的響應結果)。方法GET,HEAD,PUT,DELETE都有這種性質。一樣,方法OPTIONS和TRACE不該該有反作用,所以具備內在的等冪性。然而,有可能幾個請求的序列是不等冪的,即便在那樣的序列中全部方法都是等冪的。(若是整個序列總體的執行的結果老是相同的,而且此結果不會由於序列的總體,部分的再次執行而改變,那麼此序列是等冪的。)例如,一個序列是非等冪的若是它的結果依賴於一個值,此值在之後相同的序列裏會改變。架構

根據定義,一個序列若是沒有反作用,那麼此序列是等冪的(假設在資源集上沒有並行的操做)。jsp

9.2 OPTIONS(選項)

OPTIONS方法代表請求想獲得請求/響應鏈上關於此請求裏的URI(Request-URI)指定資源的通訊選項信息。此方法容許客戶端去斷定請求資源的選項和/或需求,或者服務器的能力,而不須要利用一個資源動做(譯註:使用POST,PUT,DELETE方法)或一個資源獲取(譯註:用GET方法)方法。分佈式

這種方法的響應是不能緩存的.。

若是OPTIONS請求消息裏包括一個實體主體(當請求消息裏出現Content-Length或者Transfer-Encoding頭域時),那麼媒體類型必須經過Content-Type頭域指明。雖然此規範沒有定義如何使用此實體主體,未來的HTTP擴展可能會利用OPTIONS請求的消息主體去獲得服務器得更多信息。一個服務器若是不支持OPTION請求的消息主體,它會遺棄此請求消息主體。

若是請求URI是一個星號(''),,OPTIONS請求將會應用於服務器的全部資源而不是特定資源。由於服務器的通訊選項一般依賴於資源,因此」」請求只能在「ping」或者「no-op」方法時纔有用;它幹不了任何事情除了容許客戶端測試服務器的能力。例如:它能被用來測試代理是否遵循HTTP/1.1。

若是請求URI不是一個星號('*'),,OPTIONS請求只能應用於請求URI指定資源的選項。

200響應應該包含任何指明選項性質的頭域,這些選項性質由服務器實現而且只適合那個請求的資源(例如,Allow頭域),但也可能包一些擴展的在此規範裏沒有定義的頭域。若是有響應主體的話也應該包含一些通訊選項的信息。這個響應主體的格式並無在此規範裏定義,可是可能會在之後的HTTP裏定義。內容協商可能被用於選擇合適的響應格式。若是沒有響應主體包含,響應就應該包含一個值爲「0」的Content-Length頭域。

Max-Forwards請求頭域可能會被用於針對請求鏈中特定的代理。當代理接收到一個OPTIONS請求,且此請求的URI爲absoluteURI,而且此請求是能夠被轉發的,那麼代理必需要檢測Max-Forwards頭域。若是Max-Forwards頭域的值爲「0」,那麼此代理不能轉發此消息;而是,代理應該以它本身的通訊選項響應。若是Max-Forwards頭域是比0大的整數值,那麼代理必須遞減此值當它轉發此請求時。若是沒有Max-Forwards頭域出如今請求裏,那麼代理轉發此請求時不能包含Max-Forwards頭域。

9.3 GET

GET方法意思是獲取被請求URI(Request-URI)指定的信息(以實體的格式)。若是請求URI涉及到一個數據生成過程,那麼這個生成的數據應該被做爲實體在響應中返回,但這並非過程的資源文本,除非資源文本剛好是過程的輸出(譯註:URI指示的資源是動態生成的)。

若是請求消息包含 If-Modified-Since,,If-Unmodified-Since,If-Match,,If-None-Match,或者 If-Range頭域,,GET的語義將變成「條件(conditionall) GET」。一個條件GET方法會請求知足條件頭域的實體。條件GET方法的目的是爲了減小沒必要要的網絡使用,這經過利用緩存的實體的更新,從而不用屢次請求或傳輸客戶已經擁有的數據。.

若是請求方法包含一個Range頭域,那麼GET方法就變成「部分Get」方法。一個部分GET會請求實體的一部分,這在14.35節裏描述了。 部分GET方法的目的是爲了減小沒必要要的網絡使用,這經過容許獲取部分實體,從而不須要傳輸客戶端已經擁有的數據。

GET請求的響應是可緩存的(cacheable)若是此響應知足第13節HTTP緩存的要求。

看15.1.3節關於GET請求用於表單時安全考慮。

9.4 HEAD

HEAD方法和GET方法一致,除了服務器不能在響應裏返回消息主體。HEAD請求響應裏HTTP頭域裏的元信息應該和GET請求響應裏的元信息一致。此方法被用來獲取請求實體的元信息而不須要傳輸實體主體(entity-body)。此方法常常被用來測試超文本連接的有效性,可訪問性,和最近的改變。.

HEAD請求的響應是可緩存的,由於響應裏的信息可能被用於更新之前的那個資源的緩存實體.。若是出現一個新的域值指明瞭緩存實體和當前源服務器上實體的不一樣(可能由於Content-Length,Content-MD5,ETag或Last-Modified值的改變),那麼緩存(cache)必須認爲此緩存項是過期的(stale)。

9.5 POST

POST 方法被用於請求源服務器接受請求中的實體做爲請求資源的一個新的從屬物。POST被設計涵蓋下面的功能。

-已存在的資源的註釋;

-發佈消息給一個佈告板,新聞組,郵件列表,或者類似的文章組。

-提供一個數據塊,如提交一個表單給一個數據處理過程。

-經過追加操做來擴展數據庫。

POST方法的實際功能是由服務器決定的,而且常常依賴於請求URI(Request-URI)。POST提交的實體是請求URI的從屬物,就好像一個文件從屬於一個目錄,一篇新聞文章從屬於一個新聞組,或者一條記錄從屬於一個數據庫。

POST方法執行的動做可能不會對請求URI所指的資源起做用。在這種狀況下,200(成功)或者204(沒有內容)將是適合的響應狀態,這依賴於響應是否包含一個描述結果的實體。

若是資源被源服務器建立,響應應該是201(Created)而且包含一個實體,此實體描述了請求的狀態而且此實體引用了一個新資源和一個Location頭域(見14.30節)。

POST方法的響應是可緩存的。除非響應裏有Cache-Control或者Expires頭域指示其響應不可緩存。然而,303(見其餘)響應能被利用去指導用戶代理(agent)去得到可緩存的響應。

POST 請求必須遵循8.2節裏指明的消息傳輸需求。

參見15.1.3節關於安全性的考慮.

9.6 PUT

PUT方法請求服務器去把請求裏的實體存儲在請求URI(Request-URI)標識下。若是請求URI(Request-URI)指定的的資源已經在源服務器上存在,那麼此請求裏的實體應該被看成是源服務器此URI所指定資源實體的修改版本。若是請求URI(Request-URI)指定的資源不存在,而且此URI被用戶代理(user agent,譯註:用戶代理可認爲是客戶瀏覽器)定義爲一個新資源,那麼源服務器就應該根據請求裏的實體建立一個此URI所標識下的資源。若是一個新的資源被建立了,源服務器必須能向用戶代理(user agent) 發送201(已建立)響應。若是已存在的資源被改變了,那麼源服務器應該發送200(Ok)或者204(無內容)響應。若是資源不能根據請求URI建立或者改變,一個合適的錯誤響應應該給出以反應問題的性質。實體的接收者不能忽略任何它不理解的Content-*(如:Content-Range)頭域,而且必須返回501(沒有被實現)響應。

若是請求穿過一個緩存(cache),而且此請求URI(Request-URI)指示了一個或多個當前緩存的實體,那麼這些實體應該被看做是舊的。PUT方法的響應不該該被緩存。

POST方法和PUT方法請求最根本的區別是請求URI(Request-URI)的含義不一樣。POST請求裏的URI指示一個能處理請求實體的資源(譯註:此資源多是一段程序,如jsp裏的servlet) 。此資源多是一個數據接收過程,一個網關(gateway,譯註:網關和代理服務器的區別是:網關能夠進行協議轉換,而代理服務器不能,只是起代理的做用,好比緩存服務器其實就是一個代理服務器),或者一個單獨接收註釋的實體。而PUT方法請求裏有一個實體一一用戶代理知道URI意指什麼,而且服務器不能把此請求應用於其餘URI指定的資源。若是服務器指望請求被應用於一個不一樣的URI,那麼它必須發送301(永久移動了)響應;用戶代理能夠本身決定是否重定向請求。

一個獨立的資源可能會被許多不一樣的URI指定。如:一篇文章可能會有一個URI指定當前版本,此URI區別於其文章其餘特殊版本的URI。這種狀況下,一個通用URI的PUT請求可能會致使其資源的其餘URI被源服務器定義。

HTTP/1.1沒有定義PUT方法對源服務器的狀態影響。

PUT請求必須遵循8.2節中的消息傳輸要求。

除非特別指出,PUT方法請求裏的實體頭域應該被用於資源的建立或修改。

9.7 DELETE(刪除)

DELETE方法請求源服務器刪除請求URI指定的資源。此方法可能會在源服務器上被人爲的干涉(或其餘方法)。客戶端不能保證此操做能被執行,即便源服務器返回成功狀態碼。然而,服務器不該該指明成功除非它打算刪除資源或把此資源移到一個不可訪問的位置。

若是響應裏包含描述成功的實體,響應應該是200(Ok);若是DELETE動做沒有經過,應該以202(已接受)響應;若是DELETE方法請求已經經過了,但響應不包含實體,那麼應該以204(無內容)響應。

若是請求穿過緩存,而且請求URI(Request-URI)指定一個或多個緩存當前實體,那麼這些緩存項應該被認爲是舊的。DELETE方法的響應是不能被緩存的。

9.8 TRACE

TRACE方法被用於激發一個遠程的,應用層的請求消息迴路(譯註:TRACE方法讓客戶端測試到服務器的網絡通路,迴路的意思如發送一個請返回一個響應,這就是一個請求響應迴路,)。最後的接收者或者是接收請求裏Max-Forwards頭域值爲0源服務器或者是代理服務器或者是網關。TRACE請求不能包含一個實體。

TRACE方法容許客戶端知道請求鏈的另外一端接收什麼,而且利用那些數據去測試或診斷。Via頭域值(見14.45)有特殊的用途,由於它能夠做爲請求鏈的跟蹤信息。利用Max-Forwards頭域容許客戶端限制請求鏈的長度去測試一串代理服務器是否在無限迴路裏轉發消息。

若是請求是有效的,響應應該在響應實體主體裏包含整個請求消息,而且響應應該包含一個Content-Type頭域值爲」message/http」的頭域。TRACE方法的響應不能不緩存。

9.9 CONNECT(鏈接)

HTTP1.1協議規範保留了CONNECT方法,此方法是爲了能用於能動態切換到隧道的代理服務器(proxy,譯註:能夠爲代理,也能夠是代理服務器)。


上邊的內容對HTTP Method 說的已經很詳細了,但冪等這個概念可能不太容易理解。下邊咱們就着重介紹下:

在HTTP/1.1規範中冪等性的定義是:

Methods can also have the property of "idempotence" in that (aside from error or expiration issues) the side-effects of N > 0 identical requests is the same as for a single request.

從定義上看,HTTP方法的冪等性是指一次和屢次請求某一個資源應該具備一樣的反作用。冪等性屬於語義範疇,正如編譯器只能幫助檢查語法錯誤同樣,HTTP規範也沒有辦法經過消息格式等語法手段來定義它,這多是它不太受到重視的緣由之一。但實際上,冪等性是分佈式系統設計中十分重要的概念,而HTTP的分佈式本質也決定了它在HTTP中具備重要地位。

爲何須要冪等性呢?咱們先從一個例子提及,假設有一個從帳戶取錢的遠程API(能夠是HTTP的,也能夠不是),咱們暫時用類函數的方式記爲:

bool withdraw(account_id, amount) 

withdraw的語義是從account_id對應的帳戶中扣除amount數額的錢;若是扣除成功則返回true,帳戶餘額減小amount;若是扣除失敗則返回false,帳戶餘額不變。值得注意的是:和本地環境相比,咱們不能輕易假設分佈式環境的可靠性。一種典型的狀況是withdraw請求已經被服務器端正確處理,但服務器端的返回結果因爲網絡等緣由被掉丟了,致使客戶端沒法得知處理結果。若是是在網頁上,一些不恰當的設計可能會使用戶認爲上一次操做失敗了,而後刷新頁面,這就致使了withdraw被調用兩次,帳戶也被多扣了一次錢。如圖1所示:

<center>


 
 

</center>

這個問題的解決方案一是採用分佈式事務,經過引入支持分佈式事務的中間件來保證withdraw功能的事務性。分佈式事務的優勢是對於調用者很簡單,複雜性都交給了中間件來管理。缺點則是一方面架構過重量級,容易被綁在特定的中間件上,不利於異構系統的集成;另外一方面分佈式事務雖然能保證事務的ACID性質,而但卻沒法提供性能和可用性的保證。

另外一種更輕量級的解決方案是冪等設計。咱們能夠經過一些技巧把withdraw變成冪等的,好比:

int create_ticket() bool idempotent_withdraw(ticket_id, account_id, amount) 

create_ticket的語義是獲取一個服務器端生成的惟一的處理號ticket_id,它將用於標識後續的操做。idempotent_withdraw和withdraw的區別在於關聯了一個ticket_id,一個ticket_id表示的操做至多隻會被處理一次,每次調用都將返回第一次調用時的處理結果。這樣,idempotent_withdraw就符合冪等性了,客戶端就能夠放心地屢次調用。

基於冪等性的解決方案中一個完整的取錢流程被分解成了兩個步驟:1.調用create_ticket()獲取ticket_id;2.調用idempotent_withdraw(ticket_id, account_id, amount)。雖然create_ticket不是冪等的,但在這種設計下,它對系統狀態的影響能夠忽略,加上idempotent_withdraw是冪等的,因此任何一步因爲網絡等緣由失敗或超時,客戶端均可以重試,直到得到結果。如圖2所示:

<center>


 
 

</center>

和分佈式事務相比,冪等設計的優點在於它的輕量級,容易適應異構環境,以及性能和可用性方面。在某些性能要求比較高的應用,冪等設計每每是惟一的選擇。

HTTP的冪等性

HTTP協議自己是一種面向資源的應用層協議,但對HTTP協議的使用實際上存在着兩種不一樣的方式:一種是RESTful的,它把HTTP當成應用層協議,比較忠實地遵照了HTTP協議的各類規定;另外一種是SOA的,它並無徹底把HTTP當成應用層協議,而是把HTTP協議做爲了傳輸層協議,而後在HTTP之上創建了本身的應用層協議。本文所討論的HTTP冪等性主要針對RESTful風格的,不過正如上一節所看到的那樣,冪等性並不屬於特定的協議,它是分佈式系統的一種特性;因此,不管是SOA仍是RESTful的Web API設計都應該考慮冪等性。下面將介紹HTTP GET、DELETE、PUT、POST四種主要方法的語義和冪等性。

HTTP GET方法用於獲取資源,不該有反作用,因此是冪等的。好比:GET http://www.bank.com/account/123456,不會改變資源的狀態,不論調用一次仍是N次都沒有反作用。請注意,這裏強調的是一次和N次具備相同的反作用,而不是每次GET的結果相同。GET http://www.news.com/latest-news這個HTTP請求可能會每次獲得不一樣的結果,但它自己並無產生任何反作用,於是是知足冪等性的。

HTTP DELETE方法用於刪除資源,有反作用,但它應該知足冪等性。好比:DELETE http://www.forum.com/article/4231,調用一次和N次對系統產生的反作用是相同的,即刪掉id爲4231的帖子;所以,調用者能夠屢次調用或刷新頁面而沒必要擔憂引發錯誤。

比較容易混淆的是HTTP POST和PUT。POST和PUT的區別容易被簡單地誤認爲「POST表示建立資源,PUT表示更新資源」;而實際上,兩者都可用於建立資源,更爲本質的差異是在冪等性方面。在HTTP規範中對POST和PUT是這樣定義的:

The POST method is used to request that the origin server accept the entity enclosed in the request as a new subordinate of the resource identified by the Request-URI in the Request-Line ...... If a resource has been created on the origin server, the response SHOULD be 201 (Created) and contain an entity which describes the status of the request and refers to the new resource, and a Location header.

The PUT method requests that the enclosed entity be stored under the supplied Request-URI. If the Request-URI refers to an already existing resource, the enclosed entity SHOULD be considered as a modified version of the one residing on the origin server. If the Request-URI does not point to an existing resource, and that URI is capable of being defined as a new resource by the requesting user agent, the origin server can create the resource with that URI.

POST所對應的URI並不是建立的資源自己,而是資源的接收者。好比:POST http://www.forum.com/articles的語義是在http://www.forum.com/articles下建立一篇帖子,HTTP響應中應包含帖子的建立狀態以及帖子的URI。兩次相同的POST請求會在服務器端建立兩份資源,它們具備不一樣的URI;因此,POST方法不具有冪等性。而PUT所對應的URI是要建立或更新的資源自己。好比:PUT http://www.forum/articles/4231的語義是建立或更新ID爲4231的帖子。對同一URI進行屢次PUT的反作用和一次PUT是相同的;所以,PUT方法具備冪等性。

在介紹了幾種操做的語義和冪等性以後,咱們來看看如何經過Web API的形式實現前面所提到的取款功能。很簡單,用POST /tickets來實現create_ticket;用PUT /accounts/account_id/ticket_id&amount=xxx來實現idempotent_withdraw。值得注意的是嚴格來說amount參數不該該做爲URI的一部分,真正的URI應該是/accounts/account_id/ticket_id,而amount應該放在請求的body中。這種模式能夠應用於不少場合,好比:論壇網站中防止意外的重複發帖。

上面簡單介紹了冪等性的概念,用冪等設計取代分佈式事務的方法,以及HTTP主要方法的語義和冪等性特徵。其實,若是要追根溯源,冪等性是數學中的一個概念,表達的是N次變換與1次變換的結果相同,有興趣的讀者能夠從Wikipedia上進一步瞭解。

參考資料

  1. https://www.quora.com/What-is-the-history-of-HTTP-verbs-PUT-GET-POST-and-DELETE
  2. http://www.cnblogs.com/weidagang2046/archive/2011/06/04/idempotence.html
  3. http://www.360doc.com/content/15/1124/19/29350465_515532644.shtml
  4. https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html
做者:老馬的春天 連接:https://www.jianshu.com/p/1a49a7b08ee0 來源:簡書 簡書著做權歸做者全部,任何形式的轉載都請聯繫做者得到受權並註明出處。
相關文章
相關標籤/搜索