C# HTTP系列8 GET與POST對比說明

  • 2019 年 10 月 5 日
  • 筆記

系列目錄 【已更新最新開發文章,點擊查看詳細】

HTTP協議,即超文本傳輸協議(Hypertext transfer protocol)。是一種詳細規定了瀏覽器和萬維網(WWW = World Wide Web)伺服器之間互相通訊的規則,通過網際網路傳送萬維網文檔的數據傳送協議。

超文本傳輸協議(HTTP)的設計目的是保證客戶機與伺服器之間的通訊。

HTTP 的工作方式是客戶機與伺服器之間的請求-應答協議。

web 瀏覽器可能是客戶端,而電腦上的網路應用程式也可能作為伺服器端。

舉例:客戶端(瀏覽器)向伺服器提交 HTTP 請求;伺服器向客戶端返迴響應。響應包含關於請求的狀態資訊以及可能被請求的內容。

在客戶機和伺服器之間進行請求-響應時,兩種最常被用到的方法是:GET 和 POST。

  • GET – 從指定的資源請求數據。
  • POST – 向指定的資源提交要被處理的數據

GET方法

查詢字元串(名稱/值對)是在 GET 請求的 URL 中發送的。 /test/demo_form.asp.net?name1=value1&name2=value2 在約定中,參數是寫在 ? 後面,用 & 分割。 解析報文的過程是通過獲取 TCP 數據,用正則等工具從數據中獲取 Header 和 Body,從而提取參數。 比如header請求頭中添加token,來驗證用戶是否登錄等許可權問題。 也就是說,可以自己約定參數的寫法,只要服務端能夠解釋出來就行,萬變不離其宗。

應用場景:

可以看到有General 、Response Headers、Request Headers。

有關 GET 請求的其他一些注釋:

  • GET 請求可被快取
  • GET 請求保留在瀏覽器歷史記錄中
  • GET 請求可被收藏為書籤
  • GET 請求不應在處理敏感數據時使用
  • GET 請求有長度限制
  • GET 請求只應當用於取回數據

POST方法

查詢字元串(名稱/值對)是在 POST 請求的 HTTP 消息主體中發送的。 POST /test/demo_form.asp.net HTTP/1.1 Host: baidu.com name1=value1&name2=value2

應用場景:

可以看到POST請求中多了Form Data(body中的一種表單請求類型)。

  • headers:主要存放cookie等其他資訊
  • body:主要存放POST的一些數據,如username:xxx

有關 POST 請求的其他一些注釋:

  • POST 請求不會被快取
  • POST 請求不會保留在瀏覽器歷史記錄中
  • POST 不能被收藏為書籤
  • POST 請求對數據長度沒有要求

GET 與 POST 比較

下面的表格比較了兩種 HTTP 方法:GET 和 POST。

GET

POST

後退按鈕/刷新

無害

數據會被重新提交(瀏覽器應該告知用戶數據會被重新提交)。

書籤

可收藏為書籤

不可收藏為書籤

快取

能被快取

不能快取

編碼類型

application/x-www-form-urlencoded

application/x-www-form-urlencoded 或 multipart/form-data。為二進位數據使用多重編碼。

歷史

參數保留在瀏覽器歷史中。

參數不會保存在瀏覽器歷史中。

對數據長度的限制

是的。當發送數據時,GET 方法向 URL 添加數據;URL 的長度是受限制的(URL 的最大長度是 2048 個字元)。

無限制。

對數據類型的限制

只允許 ASCII 字元。

沒有限制。也允許二進位數據。

安全性

與 POST 相比,GET 的安全性較差,因為所發送的數據是 URL 的一部分。 在發送密碼或其他敏感資訊時絕不要使用 GET !

POST 比 GET 更安全,因為參數不會被保存在瀏覽器歷史或 web 伺服器日誌中。

可見性

數據在 URL 中對所有人都是可見的。

數據不會顯示在 URL 中。

HTTP請求方法

HTTP請求,最初設定了八種方法。這八種方法本質上沒有任何區別。只是讓請求更加有語義而已。

下面的表格列出了其他一些 HTTP 請求方法。

方法

描述

OPTIONS

返回伺服器支援的 HTTP 請求方法。

GET

向伺服器獲取指定資源。參數放在URL後面。

HEAD

與 GET 相同,但只返回 HTTP 報頭,不返迴文檔主體。

POST

向伺服器提交數據,數據放在請求體里。

PUT

上傳指定的 URI 表示。 與POST相似,只是具有冪等特性,一般用於更新。

DELETE

刪除伺服器上的指定資源。

TRACE

回顯伺服器端收到的請求,測試的時候會用到這個。

CONNECT

把請求連接轉換到透明的 TCP/IP 通道。

GET 與 POST 本質區別

從標準上來看,GET 和 POST 的區別如下:

  • GET 用於獲取資訊,是無副作用的,是冪等的,且可快取;
  • POST 用於修改伺服器上的數據,有副作用,非冪等,不可快取。

從請求報文上來看,GET、POST的區別如下:

GET 和 POST 只是 HTTP 協議中兩種請求方式(異曲同工),而 HTTP 協議是基於 TCP/IP 的應用層協議,無論 GET 還是 POST,用的都是同一個傳輸層協議,所以在傳輸上,沒有任何區別。

如果你要給GET加上request body,技術上是完全行的通的。

如果你要給給POST帶上url參數,技術上也是完全行的通的。

但是盡量不要這麼做,請按照 GET 與 POST 的標準要求去傳遞請求參數。

在萬維網世界中,TCP就像汽車,我們用TCP來運輸數據,它很可靠,從來不會發生丟件少件的現象。但是如果路上跑的全是看起來一模一樣的汽車,那這個世界看起來是一團混亂,送急件的汽車可能被前面滿載貨物的汽車攔堵在路上,整個交通系統一定會癱瘓。為了避免這種情況發生,交通規則HTTP誕生了。 HTTP給汽車運輸設定了好幾個服務類別,有GET, POST, PUT, DELETE等等,HTTP規定,當執行GET請求的時候,要給汽車貼上GET的標籤(設置method為GET),而且要求把傳送的數據放在車頂上(url中)以方便記錄。如果是POST請求,就要在車上貼上POST的標籤,並把貨物放在車廂里。當然,你也可以在GET的時候往車廂內偷偷藏點貨物,但是這是很不光彩;也可以在POST的時候在車頂上也放一些數據,讓人覺得傻乎乎的。HTTP只是個行為準則,而TCP才是GET和POST怎麼實現的基本。

GET傳參最大長度的理解

HTTP 協議沒有 Body 和 URL 的長度限制,對 URL 限制的大多是瀏覽器和伺服器的原因。

1、正解 (1)HTTP 協議並未規定GET和POST的請求長度限制 ; (2)所謂的請求長度限制是由瀏覽器和web伺服器決定和設置的。各種瀏覽器和web伺服器的設定均不一樣,這依賴於各個瀏覽器廠家的規定或者可以根據web伺服器的處理能力來設定。IE 和 Safari 瀏覽器 限制 2k,Opera 限制4k,Firefox 限制 8k(非常老的版本 256byte),如果超出了最大長度,大部分的伺服器直接截斷,也有一些伺服器會報414錯誤。

2、各個瀏覽器和web伺服器的最大長度總結 瀏覽器 (1)IE:IE瀏覽器(Microsoft Internet Explorer) 對url長度限制是2083(2K+53),超過這個限制,則自動截斷(若是form提交則提交按鈕不起作用)。 (2)Firefox:火狐瀏覽器的url長度限制為 65536字元,但實際上有效的URL最大長度不少於100,000個字元。 (3)Chrome:Google瀏覽的url長度限制超過8182個字元返回本文開頭時列出的錯誤。 (4)Safari:Safari的url長度限制至少為 80 000 字元。 (5)Opera:Opera 瀏覽器的url長度限制為190 000 字元。Opera9 地址欄中輸入190000字元時依然能正常編輯。

伺服器 (1)Apache:Apache能接受url長度限制為8 192 字元 (2)IIS:Microsoft Internet Information Server(IIS)能接受url長度限制為16384個字元。這個是可以通過修改的(IIS7) configuration/system.webServer/security/requestFiltering/requestLimits@maxQueryStringsetting.

伺服器是因為處理長 URL 要消耗比較多的資源,為了性能和安全(防止惡意構造長 URL 來攻擊)考慮,會給 URL 長度加限制。

為什麼GET比POST更快

1、post請求包含更多的請求頭 因為post需要在請求的body部分包含數據,所以會多了幾個數據描述部分的首部欄位(如:content-type),這其實是微乎其微的。

2、最重要的一條,post在真正接收數據之前會先將請求頭髮送給伺服器進行確認,然後才真正發送數據 post請求的過程: (1)瀏覽器請求tcp連接(第一次握手); (2)伺服器答應進行tcp連接(第二次握手); (3)瀏覽器確認,並發送post請求頭(第三次握手,這個報文比較小,所以http會在此時進行第一次數據發送) ; (4)伺服器返回100 Continue響應 ; (5)瀏覽器發送數據; (6)伺服器返回200 OK響應。

get請求的過程: (1)瀏覽器請求tcp連接(第一次握手); (2)伺服器答應進行tcp連接(第二次握手); (3)瀏覽器確認,並發送get請求頭和數據(第三次握手,這個報文比較小,所以http會在此時進行第一次數據發送) (4)伺服器返回200 OK響應 。 也就是說,目測get的總耗是post的2/3左右,已經有網友進行過相關的測試。

數據包

對於GET方式的請求,瀏覽器會把http header和data一併發送出去,伺服器響應200(返回數據); 而對於POST,某些廠商的瀏覽器先發送header,伺服器響應100 continue,瀏覽器再發送data,伺服器響應200 ok(返回數據)。

因為POST需要兩步,時間上消耗的要多一點,看起來GET比POST更有效。但是請注意以下實際情況: 1、GET與POST都有自己的語義,不能隨便混用。

2、據研究,在網路環境好的情況下,發一次包的時間和發兩次包的時間差別基本可以無視。

而在網路環境差的情況下,兩次包的TCP在驗證數據包完整性上,有非常大的優點。

3、HTTP 協議中沒有明確說明 POST 會產生兩個 TCP 數據包。 並不是所有瀏覽器都會在POST中發送兩次包。 而且實際測試(Chrome、Firefox)發現就只發送一次,header 和 body 不會分開發送。

所以,header 和 body 分開發送是部分瀏覽器或框架的請求方法,不屬於 post 必然行為。

POST 方法比 GET 方法安全?【誤解】

GET請求參數是在URL後面的,數據在地址欄上可見;POST請求參數放在請求體重,數據在地址欄上不可見,因此有人說POST 比 GET 安全。 然而,從傳輸的角度來說,他們都是不安全的,因為 HTTP 在網路上是明文傳輸的,只要在網路節點上捉包,就能完整地獲取數據報文。 要想安全傳輸,就只有加密,也就是 HTTPS。

GET 會將數據快取起來,而POST不會 ?【誤解】

經測試,使用ajax採用GET方式請求靜態數據(比如html頁面,圖片)的時候,如果兩次傳輸的數據相同,第二次以後消耗的時間將會在10ms以內(chrome測試),而POST每次消耗的時間都差不多。經測試,chrome和firefox下如果檢測到GET請求的是靜態資源,則會快取,如果是數據,則不會快取,但是IE什麼都會快取起來。

是否快取數據,不同的瀏覽器廠商的實現方式不一樣。

POST不能進行管道化傳輸

《HTTP權威指南》中是這樣說的:http的一次會話需要先建立tcp連接(大部分是tcp,但是其他安全協議也是可以的),然後才能通訊,如果 每次連接都只進行一次http會話,那這個連接過程占的比例太大了!於是出現了持久連接:在http/1.0+中是connection首部中添加keep-alive值,在http/1.1中是在connection首部中添加persistent值,當然兩者不僅僅是命名上的差別,http/1.1中,持久連接是默認的,除非顯示在connection中添加close,否則持久連接不會關閉,而http/1.0+中則恰好相反,除非顯示在connection首部中添加keep-alive,否則在接收數據包後連接就斷開了。   出現了持久連接還不夠,在http/1.1中,還有一種稱為管道通訊的方式進行速度優化:把需要發送到伺服器上的所有請求放到輸出隊列中,在第一個請求發送出去後,不等到收到伺服器的應答,第二個請求緊接著就發送出去,但是這樣的方式有一個問題:不安全,如果一個管道中有10個連接,在發送出9個後,突然伺服器告訴你,連接關閉了,此時客戶端即使收到了前9個請求的答覆,也會將這9個請求的內容清空,也就是說,白忙活了……此時,客戶端的這9個請求需要重新發送。這對於冪等請求還好(比如get,多發送幾次都沒關係,每次都是相同的結果),如果是post這樣的非冪等請求(比如支付的時候,多發送幾次就慘了),肯定是行不通的。   所以,post請求不能通過管道的方式進行通訊!很有可能,post請求需要重新建立連接,這個過程不跟完全沒優化的時候一樣了么?所以,在可以使用get請求通訊的時候,不要使用post請求,這樣用戶體驗會更好,當然,如果有安全性要求的話,post會更好。管道化傳輸在瀏覽器端的實現還需考證,貌似默認情況下大部分瀏覽器(除了opera)是不進行管道化傳輸的,除非手動開啟!

系列目錄 【已更新最新開發文章,點擊查看詳細】