問題回答:Http 請求的Post 和Put 的區別

2021-03-02 測試進階

這是在我們的測試進階社群的微信討論群裡有人討論的一個面試題:

Http 請求的 post 和 put的區別是什麼?

很快有人回答「put請求單個數據」,後面提問人又去網上查了資料,查出來 put 和 post的區別是 「put 同樣的請求,前一條會被後一條覆蓋」。

接著另一位群友又發表了不同意見,並直接在群裡上傳了一個截圖:

群友不知道哪裡找來的通俗解釋

大家對這個問題看法各異,查到的資料也都不一樣。那麼到底Http 請求的 post 和 put的區別是什麼呢?特別提一下,我們不能把一些中文資料裡的通俗解釋當作標準答案。在網上查資料,我們需要培養一定的鑑別能力。

首先,這裡有一個誤區,很多沒寫過 web 應用的同學認為這兩個方法的功能區別是固有的,一定存在的。但實際上, http 請求的 post 和 put分別具體實現什麼樣的功能,都是由程式設計師在寫服務端代碼時決定的。一個 post 請求和一個 put 請求上攜帶的信息量是一樣的,同樣的 http 請求頭(header),同樣的 http 請求體(body),唯一不同的是請求方法名,一個叫 post,一個叫 put。理論上來說程式設計師完全可以實現功能一樣的處理函數來處理 post 請求和 put請求。

例1:程式設計師其實完全可以實現相同的 post 和 put請求的處理函數,以下使用的是hug框架。

import hug
@hug.post()
def post_a_user(user):
return {"your_input":user+"X"}

@hug.put()
def put_a_user(user):
return {"your_input":user+"X"}

但是,既然攜帶的信息量相同,具體功能也是程式設計師自行決定,為什麼 http 協議裡要有 post 方法 和 put 方法兩個方法呢?原來,在 http協議裡,對 post 和 put是有官方建議的使用方法的(其實對所有http請求方法都有官方建議用法。)網際網路的網絡協議是在RFC裡定義的,在網上,我們可以查到定義http協議的RFC。在w3c的網站上,我們可以找到HTTP協議相關的RFC:https://www.w3.org/Protocols

最早的是1999年的 RFC2616和 RFC2617,其中RFC2616裡9.6節專門寫了 Post 和 Put 的區別。

以下是RFC2616在網絡上流傳的中文版中對 Post 和 Put的區別的描述:

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

但之後RFC 2616在2014年被廢棄,改為 RFC 723X系列。

在 RFC 7231 (https://tools.ietf.org/html/rfc7231)裡4.3.3 Post 和4.3.4 Put 分別講解了這兩個方法。其中,也有對 Post 和 Put 區別的官方描述:但是很遺憾,我暫時搜不到RFC 7231中文翻譯版。以下只能是我個人嘗試按照自己理解翻譯一下了,翻譯水平有限,建議大家還是看原版。

POST方法和PUT方法請求最根本的區別是發起請求的目的不同。post 請求的目的是根據資源自身的語義來處理這個資源(譯註:我理解這個意思就是說,post請求可以根據實際請求的資源來決定到底怎麼處理,原文中4.3.3節給了一些例子。我會把我的翻譯版附在本文末尾。)。put請求的目的是用來替換整個目標資源。put 請求具有 冪等性(idempotent)。(冪等性的意思在這個RFC的4.2.2裡說了「同樣的請求,不管發多少次,每次伺服器處理完之後的結果,都和只發一次是一樣的。」這裡我舉個例子幫助大家理解:你的伺服器端存放了一個文章收藏夾,你通過一個put請求來修改收藏夾裡的文章名字,這個 put 請求的請求體裡包含了整個文章收藏夾裡所有文章的名字。當服務端處理這個請求時,只要從 put 請求裡拿出這個文章名字列表,整個存到伺服器上,就是一個完整的新的收藏夾。那麼這樣的put 請求,無論你是發一次,還是發多次,假設伺服器都能成功處理,那麼最終對伺服器造成的影響都是一樣的:即伺服器端原有的收藏夾裡的文章列表被替換成了put請求裡帶的收藏夾的文章列表。)

除了冪等性(idempotent),官方文檔裡還有其他的一些詳細介紹,比如緩存性,post 是可以被緩存的,put 卻不行。RFC文檔裡put 請求的介紹特別長。我猜你如果在面試時能跟面試官講一講冪等性之類的http方法的特性,再挑剔的面試官也會滿意的吧。而除了這個官方給的最根本區別以外,我們還可以結合實際工作經驗中用到的 post 和 put 來談一談這兩者的區別。畢竟,官方只是提供了這兩個請求方法,然後要求大家去用,但程式設計師真實使用的web 框架未必要求大家百分百按照 http協議來對請求做處理。

那如果你做的項目裡根本沒用到這些方法,或者你們的開發把服務端邏輯寫得很有個性沒按協要求來。。。 那可以試試來參加我們的項目實戰,這次的項目實戰裡用的 Github api 可是會用到大多數 http 請求方法的。而且 Github 的http 接口本身實現也比較規範,屬於比較有參考價值的。

最後附上我翻譯的一個半的RFC7231的小節(post的翻完了,put的翻了一小半。。實在太長,需要的可以閱讀原文):

4.3.3 post

服務端在處理時post方法發出的請求時,應該按照請求的具體資源的具體語義來對該資源做相應的處理。例如,以下情況一般使用 Post 方法:

服務端根據這些數據處理的實際結果來選擇一個Http響應狀態碼。除了206 (Partial Content), 304 (Not Modified), and 416 (Range Not Satisfiable) 這三個以外的 http響應狀態碼都可以作為 Post 請求的響應狀態碼。

如果post請求希望創建一個或多個資源,並且服務端把這些資源成功創建了,那麼應該(原文大寫的SHOULD)返回一個 201 (Created) 並且在響應頭(response header)裡加入Location欄位,值為創建出來的資源的id。並返回「a representation that describes the status of the request while referring to the new resource(s)」 (譯註:這一段每個詞我都認識,但連起來我就看不懂了。。。)

Post 請求的響應在響應裡明確包含了freshness信息時,這個響應是可緩存的。然而 Post 請求的緩存機制並沒有被廣泛實現和應用。假如服務端真的希望客戶端能夠利用緩存機制來緩存一個post請求的響應裡的信息(也就是這個post創建出來的資源的URI),並且在後面的get 請求裡重用這些被緩存的信息,那麼服務端可以返回一個 狀態碼為200(OK)的響應,並且在響應頭裡包含 Content-location這個欄位,其值為 post請求創建的資源URI。

如果post請求希望創建一個或多個資源,但服務端發現這些資源本來就存在,服務端可以回復一個303 (See Other),表示希望客戶端進行重定向。同時在響應頭裡加入Location欄位,值為現有的這個資源的id。

4.3.4 put

put方法用於創建或者替換整個資源,請求體(body)裡包含這個資源的完整描述。一個 put 請求如果成功了,那麼理論上來說,對同樣的 url 做一個 get 請求,應該能得到一個  200 (OK) 的響應。但實際上,並不能保證get 到200的響應。因為,可能同時有其他人也在對這個資源做操作,那麼就可能在get請求抵達伺服器之前,這個資源已經被別人改掉了。所以說, put 請求成功,只能代表在這個請求被伺服器處理的那個時刻上,這個資源被創建或替換成請求體裡的樣子了。(譯註:比如我用put請求修改一個小組裡的所有用戶列表,我的請求體裡包含了小組裡所有用戶的用戶名列表,那麼在伺服器處理我這個請求,並告訴我成功了的那個時刻,這個小組的用戶名一定和我發的put請求裡的用戶名列表是一樣的。但是同時有可能有別的人也在嘗試改這個小組的信息,那麼我緊接著發一個 get 請求,可能get到的小組裡的用戶名列表跟我剛才put的已經不一樣了。)

如果put請求希望創建一個或多個資源,並且服務端把這資源成功創建了,那麼服務端必須(原文大寫的MUST)給用戶返回一個狀態碼為 201 (Created) 的響應。而如果這個請求是用來修改某個資源的狀態的,那麼服務端 必須(MUST)返回一個狀態碼為 200 (OK) 的響應或者一個狀態碼為 204 (No Content)的響應。 200 和204 都表示成功完成了這個請求。

服務端應該(SHOULD)忽略 put請求頭裡無法識別出含義的欄位,而不應該把header裡的這些欄位也存在資源裡。

(關於 PUT的 描述太長了,後面還有整整兩頁沒翻,以後有空接著翻譯吧。。。或者哪位讀者感興趣可以翻一下。)

如果你還沒有正式加入本社群,請掃描下方二維碼加入。

本社群致力於提高測試人員的技術水平,提供了完整的 Python 入門教程及練習、接口測試入門教程,以及現在正式開展的接口測試項目實戰。此外還有答疑和討論等,加入本社群,還相當於加入了189位小夥伴(截止2019年3月2日)的人脈圈,可以獲取各種內推機會,了解業內行情。現在加入只需要支付128元/年的年費。最後,如果希望得到免費體驗機會的話,可以加我微信89507288獲取體驗卡。

相關焦點

  • PHP面試題:put與post的區別
    不知道存在put這種方式http協議規定了四種資源訪問形式:get、post、put、delete。不知道區別,那put與post有哪些區別呢從方法語義是不同的,put是上傳資源,post是修改資源, 但是實際使用中,無論是上傳還是修改,我們還是post方法提交請求頭報文不同: post方式:post /index.php http/1.1
  • HTTP POST請求步驟詳解
    HTTP POST請求是使用post方式提交http請求,來獲取數據。該步驟有「常規」、「欄位」兩個標籤頁。「常規」標籤頁配置信息如圖1所示。
  • 我終於知道post和get的區別
    碼農:你知道get和post請求到底有什麼區別?程式設計師:你看這篇就知道了。碼農:你月薪三萬了?程式設計師:嗯。碼農:你是怎麼做到的?程式設計師:我做夢做到的前言這個問題幾乎面試的時候都會問到,是一個老生常談的話題,然而隨著不斷的學習,對於以前的認識有很多誤區,所以還是需要不斷地總結的,學而時習之,不亦說乎。
  • 必須知道的get和post的區別
    get、post常見的區別get和post不同點的誤區附錄常見的http狀態碼1.什麼是http這裡只是簡單概述一下,更多詳情可以參見:基於tcp/ip、一種網絡應用層協議、超文本傳輸協議HyperText Transfer
  • HTTP協議請求(request)和響應(response)報文分析
    完成了TCP三次握手後,客戶端會向伺服器發出一個請求報文。請求報文的格式如下圖抓包所示:前三行為請求行,其餘部分稱為request-header。請求行中的method表示這次請求使用的是get方法。請求方法的種類比較多,如option,get,post,head,put,delete,trace等,常用的主要是get,pos。
  • HTTP|GET 和 POST 區別?
    這和網上流傳的說法一致。但是這只是HTML標準對HTTP協議的用法的約定。怎麼能當成GET和POST的區別呢?而且,現代的Web Server都是支持GET中包含BODY這樣的請求。雖然這種請求不可能從瀏覽器發出,但是現在的Web Server又不是只給瀏覽器用,已經完全地超出了HTML伺服器的範疇了。
  • 接口測試實戰| GET/POST 請求區別詳解
    在日常的工作當中,HTTP 請求中使用最多的就是 GET 和 POST 這兩種請求方式。
  • Python接口自動化-requests模塊之post請求
    以下,主要介紹requests模塊中的post請求的使用。>post請求參數解析:data、json區別小夥伴們看完可能有點懵逼,data和json有啥區別呀,什麼時候傳入data,什麼時候傳入json。
  • Get 和 Post 區別
    瀏覽器的get和post有什麼區別?第1個從他們字面意思去理解這些,就是從網頁上獲取一個數據。然後這個獲取數據是對伺服器不會產生副作用的,術語就是數學上的 冪等即多次操作不產生影響(比如任何數乘1或者乘0,多次乘之後,都不會變化),那樣多次操作也不會去產生副作用。
  • jQuery的$.get()、$.post()和$.ajax()以GET/POST方式請求數據
    ,如get、post、put、deletet等,但是最常用的是獲取數據和提交數據,獲取數據是get請求,提交數據是post請求。GET請求時,Url地址是暴露出來的,大家都可以看,且還可以收藏起來以便下次使用。HTTP POST請求:一般情況下是指將本地的數據提交到遠程的伺服器上去處理和存儲。POST請求時,URL地址是隱藏起來的,不能被收藏。
  • 都 9102 年了,還問 GET 和 POST 的區別
    post 的區別,而搜索出來的答案並不能讓我們裝得一手好逼,那就讓我們從 HTTP 報文的角度來擼一波,從而搞明白他們的區別。注意,並不是說標準答案有誤,上述區別在大部分瀏覽器上是存在的,因為這些瀏覽器實現了 HTTP 標準。但是,前面列舉的只是瀏覽器實現上的區別,而不是 get 和 post 的本質區別。3 GET 和 POST 報文上的區別先下結論,GET 和 POST 方法沒有實質區別,只是報文格式不同。
  • 99%的人理解錯 HTTP 中 GET 與 POST 的區別
    最直觀的區別就是GET把參數包含在URL中,POST通過request body傳遞參數。你可能自己寫過無數個GET和POST請求,或者已經看過很多權威網站總結出的他們的區別,你非常清楚知道什麼時候該用什麼。當你在面試中被問到這個問題,你的內心充滿了自信和喜悅。
  • 99%的人都理解錯了HTTP中GET與POST的區別
    GET和POST是HTTP請求的兩種基本方法,要說它們的區別,接觸過WEB開發的人都能說出一二。 最直觀的區別就是GET把參數包含在URL中,POST通過request body傳遞參數。
  • 美團面試官,一上來,就叫我說Post和Get的區別?我慌了...
    碼農:你知道get和post請求到底有什麼區別?程式設計師:你看這篇就知道了。碼農:你月薪三萬了?程式設計師:嗯。碼農:你是怎麼做到的?程式設計師:我做夢做到的這個問題幾乎面試的時候都會問到,是一個老生常談的話題,然而隨著不斷的學習,對於以前的認識有很多誤區,所以還是需要不斷地總結的,學而時習之,不亦說乎。
  • python接口自動化2-發送post請求
    前言發送post的請求參考例子很簡單,實際遇到的情況卻是很複雜的,首先第一個post請求肯定是登錄了,但登錄是最難處理的。
  • HTTP PUT方法利用的幾種方式
    TRACE方法,這個方法比較出乎意料,它是響應體中返回的判斷方法,即整個HTTP請求。這包括請求體,也包括請求頭,比如cookies和認證頭等。   進入正題   識別HTTP伺服器最簡單最基本的形式就是查看HTTP響應頭中色server欄位。
  • 99%的人都理解錯了HTTP中GET、POST之間的區別與聯繫
    最直觀的區別就是GET把參數包含在URL中,POST通過request body傳遞參數。你可能自己寫過無數個GET和POST請求,或者已經看過很多權威網站總結出的他們的區別,你非常清楚知道什麼時候該用什麼。當你在面試中被問到這個問題,你的內心充滿了自信和喜悅。
  • Go中的HTTP請求之——HTTP1.1請求流程分析
    如果URL和rt為nil則直接返回錯誤。同時, 如果請求中設置了用戶信息, 還會檢查並設置basic的驗證頭信息,最後調用rt.RoundTrip得到請求的響應。由上可知, 每次for循環, 會判斷請求上下文是否已經取消, 如果沒有取消則繼續進行後續的流程。先調用t.getConn方法獲取一個persistConn。因為本篇主旨是http1.1,所以我們直接看http1.1的執行分支。根據源碼中的注釋和實際的debug結果,獲取到連接後, 會繼續調用pconn.roundTrip。
  • 在PHP中使用CURL實現GET和POST請求的方法
    1.CURL介紹CURL是一個利用URL語法規定來傳輸文件和數據的工具.支持很多協議,如HTTP、FTP、TELNET等。
  • POST請求 報 HTTP status 415 錯誤(postman測試)
    今天用postman測試uat環境接口時遇到了一個問題?測試時出現了HTTP status 415 錯誤。感覺很疑惑,有點懵,在網上找了些資料,總算知道為什麼出現這個問題了,記錄下來,防止自己以後再出現這個問題,也正好分享給各位同學,希望都同學們有所幫助。