對於這個問題,相信很多人都能給出壹個標準的答案,就像下面列出的幾條:
這裏列出的幾點可能還不全,但涵蓋了GET和POST主要的幾點區別。我此前也是像這樣表面地理解GET和POST請求的,不過最近在使用Postman時讓我產生了壹些疑惑。
這裏提交壹個簡單的GET請求,正常情況參數我們都是在Query Params中添加,就像下圖這樣:
這種情況下請求的參數是在url中的,和我們所認知的GET請求是壹致的,通過查看請求報文信息也能看出,該請求是沒有請求體的。
如果我們把參數放到請求體中提交會怎麽樣呢?這次我們在body中添加參數,格式先選擇 application/x-www-form-urlencoded ,後面我會具體解釋這個屬性的意義。
這種情況下依然可以請求成功得到響應數據,此時參數沒有體現在url中,查看請求報文後發現參數確實是在請求體中的。
這種情況和我們所認知的GET請求就不太壹樣了,GET請求竟然也能通過請求體來提交參數。
接下來我又測試了壹下POST請求,發現請求參數既可以通過請求體來提交,也能像GET請求那樣拼接在url後面來提交。
這讓我很困惑,看起來GET請求和POST好像沒有區別,後來通過 GET和POST兩種基本請求方法的區別 這篇文章我找到了答案。HTTP協議的底層是TCP/IP,所以GET和POST請求的底層也是TCP/IP,都是TCP鏈接,它們能做的事情是壹樣的。所以, GET請求通過請求體提交參數,POST請求通過url提交參數,在技術上是完全行的通的。
這篇文章中使用的壹個比喻很是貼切,這裏直接引用壹下,在網絡世界中,將TCP比作汽車,我們用TCP來運輸數據,它很可靠,從來不會發生丟件少件的現象。但是如果路上跑的全是看起來壹模壹樣的汽車,那這個世界看起來是壹團混亂,送急件的汽車可能被前面滿載貨物的汽車攔堵在路上,整個交通系統壹定會癱瘓。為了避免這種情況發生,交通規則HTTP誕生了。HTTP給汽車運輸設定了好幾個服務類別,有GET、 POST、 PUT、DELETE等等,HTTP規定當執行GET請求的時候,要給汽車貼上GET的標簽(設置method為GET),而且要求把傳送的數據放在車頂上(url中)以方便記錄。如果是POST請求,就要在車上貼上POST的標簽,並把貨物放在車廂裏(請求體中)。當然,妳也可以在GET的時候往車廂內偷偷藏點貨物,但是這是很不光彩;也可以在POST的時候在車頂上也放壹些數據,讓人覺得傻乎乎的。HTTP只是個行為準則,而TCP才是GET和POST怎麽實現的基本。
對於GET請求參數的大小限制,我們知道是由於url長度的限制導致的,但其實url的長度並不是GET請求限制的,而是特定的瀏覽器及服務器的限制,將不同的瀏覽器和服務器比作不同的運輸公司,雖然理論上可以在車頂上無限地堆貨物(url中無限加參數),但是運輸公司可不傻,裝貨和卸貨也是有很大成本的,他們會限制單次運輸量來控制風險,數據量太大對瀏覽器和服務器都是很大負擔。業界不成文的規定是,(大多數)瀏覽器通常都會限制url長度在2K個字節,而(大多數)服務器最多處理64K大小的url,超過的部分恕不處理。 因此使用POST請求通過url傳遞參數並不能保證參數壹定能被接收到 。同理,如果妳用GET請求,在請求體中偷偷藏了數據,不同服務器的處理方式也是不同的,有些服務器會幫妳卸貨,讀出數據,有些服務器直接忽略,所以, 雖然GET請求可以使用請求體提交參數,也不能保證參數壹定能被接收到 。
總結壹下可以得出結論,GET請求和POST請求本質上是壹樣的,GET請求通過請求體提交參數和POST請求通過url提交參數都是可行的,但是並不推薦這樣做,因為並不能保證服務器可以接受到這種方式傳遞的參數。
此外,這篇文章還提出了GET請求和POST請求的另壹點區別,我們可能知道POST請求要比GET請求慢壹下,這是什麽原因導致的呢?因為 GET請求產生壹個TCP數據包,而POST請求會產生兩個TCP數據包 。對於GET請求,瀏覽器會把Http header和data壹並發送出去,服務器響應200(ok);而對於POST請求,瀏覽器先發送header,服務器響應100(continue),瀏覽器再發送data。正是因為POST請求會發送兩次包,所以相對會慢壹些。但是需要註意,並不是所有瀏覽器都會在POST請求中發送兩次包,Firefox就只發送壹次。
我們知道HTTP Header中有壹個Content-Type屬性,表示請求或響應中的數據格式。根據此前的分析,GET請求壹般都是通過url傳遞參數的,因此沒有請求體,除非顯式設置,否則請求頭中沒有Content-Type字段。而POST請求則要通過請求體提交參數,因此請求頭中會有Content-Type字段,因此後面的示例都采用POST請求。
Content-Type在Header中的格式如下:
下面就讓我們來看壹下HTTP中常見的幾種Content-Type。
這是最常見的數據編碼格式,請求參數被編碼成鍵值對格式,例如key1=val1&key2=val2,中文或特殊字符如"/"、","、“:" 等會自動進行URL轉碼。不支持文件,壹般用於表單提交。結合Postman來看壹下:
POST請求提交普通的參數(不含文件)壹般都是采用這種數據格式。
這種方式多用於POST請求上傳文件,我們依然通過Postman來看壹下:
可以看到Content-Type有些不同,在multipart/form-data後面還拼接了壹個boundary,它的作用是分割不同的請求參數。在請求實體裏每個參數對應壹個塊,以boundary分割符開始,下壹行是 Content-Disposition ,包含了參數類型和參數名,這裏的類型是form-data,表示是表單上傳,如果參數是文件還會有壹個filename參數,值就是文件名稱。在這之後有壹個空行,最後是參數的值。請求體的最後也會以boundary作為結束的標識。
表示提交的數據是壹段Json字符串,服務端/客戶端接收到請求/響應時再按照Json格式進行解析。
還有幾個相似的類型,比如 application/xml 表示傳遞xml格式數據; text/plain 表示直接上傳壹段純文本等等,這些都屬於上傳文本信息,區別只是文本格式不同。
上面的示例中展示的都是請求頭中的Content-Type,在響應頭中也會有Content-Type字段,表示響應數據的格式。在移動開發中,我們請求服務端返回的響應數據壹般都是json字符串,Content-Type基本上都是application/json,也有返回text/*類型的( * 可以是任意類型),本質上返回的數據都是文本,區別只是文本格式不同,使用Postman可以看出區別,對於Content-Type=application/json,Postman會將Json文本自動格式化,而對於Content-Type=text/plain,返回數據不會做任何處理,就是壹段純文本。
由於我不是很懂服務端開發,所以並沒有過多關註過響應的Content-Type,有些地方可能說得不對,歡迎大家指正。
Content-Type的種類還有很多,大多數我們在開發中可能並不會用到,感興趣的話可以查看 HTTP content-type 對照表 。
1.GET請求和POST請求本質上是壹樣的,參數都可以通過url或者請求體來提交,但是並不能確保參數都可以收到。在實際開發中,除非遇到特殊情況,GET請求使用url傳遞參數,POST請求參數通過請求體提交。
2.Content-Type決定了數據在請求體/響應體中的格式。對於GET請求,壹般無需指定Content-Type;對於POST請求,需要根據提交的參數類型來指定對應的Content-Type。
GET和POST兩種基本請求方法的區別
Content-Type 詳解