HTTP協議與HTML表單(再談GET與POST的區別)

做者:darxin html

HTTP的GET/POST方式有何區別?這是一個老生常談的問題,但老生常談的問題每每有一些讓人誤解的結論。本文將帶您淺嘗HTTP協議,在瞭解HTTP協議的同時將會展現許多被人們忽視的內容。在掌握了HTTP協議的過程當中咱們將天然而然地瞭解到GET與POST的本質區別。 瀏覽器

 

 

HTTP請求

從使用者的角度看,一個HTTP請求起始於
用戶端瀏覽器上輸入的一個URL地址;
網頁中的一個超連接;
提交一個HTML表單。
但本質上說,一個HTTP請求起始於用戶端向HTTP服務器發送的一個URL請求。 安全

一個標準的HTTP請求由如下幾個部分組成 服務器

<request-line>
<headers>
<CRLF>
[<request-body><CRLF>] app

在HTTP請求中,第一行是請求行(request-line),用來講明請求類型、要訪問的資源(URL)以及使用的HTTP版本;
緊接着是多行頭部(headers)信息,用來講明服務器要使用的附加信息;
頭部信息以後是一個回車換行符(/r/n),用於標明頭部信息的結束。
以上是必須內容,根據須要可在頭部信息結束以後增長主體數據(request-body);
主體數據以後是一個回車換行符(/r/n),用於標明主體數據的結束。 jsp

 

須要注意的是
請求行(request-line)中的URL部分必須以application/x-www-form-urlencoded方式編碼。
主體數據(request-body)的編碼方式由頭部(headers)信息中的Content-Type指定。
主體數據(request-body)的長度由頭部(headers)信息中的Content-Length指定。 工具

 

例如,咱們能夠在IE瀏覽器上輸入下面的網址: 編碼

http://localhost:8000/hello/index.html url

HTTP請求的頭部信息以下: spa

GET /hello/index.html HTTP/1.1
Accept: */*
Accept-Language: zh-cn
Accept-Encoding: gzip, deflate
Host: localhost:8000
Connection: Keep-Alive
Cookie: JSESSIONID=BBBA54D519F7A320A54211F0107F5EA6

 

[End]

上述信息沒有request-body部分,這是以GET方式發送的HTTP請求。若是請求中須要附加主體數據,即增長request-body部分,則必須使用POST方式發送HTTP請求。HTML超連接(<a></a>)只能用GET方式提交HTTP請求,HTML表單(<form></form>)則可使用兩種方式提交HTTP請求。

 

 

HTML表單

HTML表單的使用方法以下:

[xhtml]  view plain copy
  1. <form action="目標地址" method="發送方式" enctype="數據主體的編碼方式">  
  2.     <!-- 各種型的表單域 -->  
  3.     <input name="NAME" value="VALUE"/>  
  4.     <textarea name="NAME">VALUE</textarea>  
  5.     <select name="NAME">  
  6.         <option value="VALUE" selected="selected"/>  
  7.     </select>  
  8. </form>  

表單中存在各類類型的表單域標籤,如<input/>、<textarea/>及<select/>。每一種表單域標籤均有NAME與VALUE兩種標籤屬性。這兩個標籤屬性決定了表單提交時傳送的屬性名及相應的值。

目標地址(URL)

action標籤屬性指定了表單提交的目標地址,其值能夠是完整的URL。如:

<form action="http://localhost:8000/hello/checkUser.html"></form>

若是放置表單的網頁與表單提交的目標地址在同一個HTTP服務器上,則目標地址能夠用絕對路徑表示(絕對路徑相對於HTTP服務器)。絕對路徑以「/」開頭,包括WEB應用上下文及請求。如:

<form action="/hello/checkUser.html"></form>

若是放置表單的網頁與表單提交的目標地址在同一個WEB應用上下文上,則目標地址能夠用相對路徑表示(相對路徑相對於放置表單的網頁)。相對路徑不以「/」開頭,不包括WEB應用上下文。如:

<form action="checkUser.html"></form>

須要注意的是,action標籤屬性的值必須符合URL的要求,其編碼必須符合application/x-www-form-urlencoded編碼規則。以下面的表單:

[xhtml]  view plain copy
  1. <!-- 不符合要求的表單 -->  
  2. <form action="checkUser.html?opt=中文" method="POST">  
  3. </form>  

這樣的表單是不符合要求的。若是其URL值存在非法字符(如中文字符),應將其進行URL Encoding處理。URL Encoding的處理方法以下:

  • 字母數字字符 "a" 到 "z"、"A" 到 "Z" 和 "0" 到 "9" 保持不變。
  • 特殊字符 "."、"-"、"*" 和 "_" 保持不變。
  • 空格字符 " " 轉換爲一個加號 "+"。
  • 全部其餘字符都是不安全的,所以首先使用一種編碼機制將它們轉換爲一個或多個字節。而後對每一個字節用一個包含 3 個字符的字符串 "%xy" 表示,其中 xy 爲該字節的兩位十六進制表示形式。推薦的編碼機制是 UTF-8。

將「中文」兩個字符進行URL Encoding所獲得的值就是「%E4%B8%AD%E6%96%87」。

因此正確的表單應該是:

[xhtml]  view plain copy
  1. <!-- 符合要求的表單 -->  
  2. <form action="checkUser.html?opt=%E4%B8%AD%E6%96%87" method="POST">  
  3. </form>  

發送方式

method標籤屬性指定了表單的發送方式,發送方式只有兩種:GET及POST。
當以GET方式發送表單時,發送的HTTP請求沒有request-body部分,因此不須要指定enctype標籤屬性。

GET方式只提交表單域中的數據,action標籤屬性中若是存在?子句,GET方式將不予處理。以下面的表單:

[xhtml]  view plain copy
  1. <form action="checkUser.html?opt=xxx" method="GET">  
  2.     <input type="text" name="username" value="yyy"/>  
  3.     <input type="text" name="age" value="zzz"/>  
  4.     <input type="submit" value="submit"/>  
  5. </form>  

表單提交時沒有包括opt屬性,HTTP頭部信息以下:

GET /hello/checkUser.html?username=yyy&age=zzz HTTP/1.1
Referer: http://localhost:8000/hello/index.html
Accept: */*
Accept-Language: zh-cn
Accept-Encoding: gzip, deflate
Host: localhost:8000
Connection: Keep-Alive
Cookie: JSESSIONID=BBBA54D519F7A320A54211F0107F5EA6

 

[End]

須要注意的是,以GET方式提交表單時,每一個表單域的NAME與VALUE要以URL的方式提交,因此每一個表單域的NAME與VALUE均要進行URL Encoding處理。這個操做一般是由用戶端瀏覽器完成的。以下面的表單:

[xhtml]  view plain copy
  1. <form action="checkUser.html" method="GET">  
  2.     <input type="hidden" name="opt" value="中文"/>  
  3.     <input type="text" name="username" value="yyy"/>  
  4.     <input type="text" name="age" value="zzz"/>  
  5.     <input type="submit" value="submit"/>  
  6. </form>  

其中表單域opt的VALUE是中文字符「中文」,在表單提交時,用戶端瀏覽器會自動將其進行URL Encoding。HTTP頭部信息以下:

GET /hello/checkUser.html?opt=%E4%B8%AD%E6%96%87&username=yyy&age=zzz HTTP/1.1
Referer: http://localhost:8000/hello/index.html
Accept: */*
Accept-Language: zh-cn
Accept-Encoding: gzip, deflate
Host: localhost:8000
Connection: Keep-Alive
Cookie: JSESSIONID=BBBA54D519F7A320A54211F0107F5EA6

 

[End]

 

當以POST方式發送表單時,表單域中的數據將做爲request-body提交,action標籤屬性中的?子句將在request-line中得以保留。以下面的表單:

[xhtml]  view plain copy
  1. <form action="checkUser.html?opt=xxx" method="POST">  
  2.     <input type="text" name="username" value="yyy"/>  
  3.     <input type="text" name="age" value="zzz"/>  
  4.     <input type="submit" value="submit"/>  
  5. </form>  

表單提交時,HTTP頭部信息以下:

POST /hello/checkUser.html?opt=xxx HTTP/1.1
Referer: http://localhost:8000/hello/index.html
Accept: */*
Accept-Language: zh-cn
Content-Type: application/x-www-form-urlencoded
Accept-Encoding: gzip, deflate
Host: localhost:8000
Content-Length: 20
Connection: Keep-Alive
Cache-Control: no-cache
Cookie: JSESSIONID=BBBA54D519F7A320A54211F0107F5EA6

 

username=yyy&age=zzz
[End]

須要注意的是,以POST方式提交表單時,action標籤屬性的值必須是已經進行了URL Encoding處理以後的值,用戶端瀏覽器不會自動處理URL中的非法字符。以下面的表單是不符合要求的:

[xhtml]  view plain copy
  1. <!-- 不符合要求的表單 -->  
  2. <form action="checkUser.html?opt=中文" method="POST">  
  3.     <input type="text" name="username" value="yyy"/>  
  4.     <input type="text" name="age" value="zzz"/>  
  5.     <input type="submit" value="submit"/>  
  6. </form>  

正確的表單應該是:

[xhtml]  view plain copy
  1. <form action="checkUser.html?opt=%E4%B8%AD%E6%96%87" method="POST">  
  2.     <input type="text" name="username" value="yyy"/>  
  3.     <input type="text" name="age" value="zzz"/>  
  4.     <input type="submit" value="submit"/>  
  5. </form>  

數據主體的編碼方式

在HTTP請求中,request-line老是以application/x-www-form-urlencoded方式編碼。enctype標籤屬性只對request-body起做用。也就是說只有在method="POST"的狀況下,設置enctype才起做用。
設置enctype標籤屬性後,在HTTP請求的頭部(headers)信息中會多出一行Content-Type信息,而且request-body部分將會以Content-Type指定的MIME進行編碼。這些操做都是由客戶端瀏覽器自動完成的。

 

在沒有指定enctype標籤屬性時,表單以默認的application/x-www-form-urlencoded方式對request-body進行編碼。
若是表單域中的NAME或VALUE含有非法字符(如中文字符),客戶端瀏覽器會自動對其進行URL Encoding處理。以下面的表單:

[xhtml]  view plain copy
  1. <form action="checkUser.html" method="POST">  
  2.     <input type="hidden" name="opt" value="中文"/>  
  3.     <input type="text" name="username" value="yyy"/>  
  4.     <input type="text" name="age" value="zzz"/>  
  5.     <inupt type="submit" value="submit"/>  
  6. </form>  

表單提交時,HTTP頭部信息以下:

POST /hello/checkUser.html HTTP/1.1
Accept: */*
Referer: http://localhost:8000/hello/index.jsp
Accept-Language: zh-cn
Content-Type: application/x-www-form-urlencoded
Accept-Encoding: gzip, deflate
Host: localhost:8000
Content-Length: 43
Connection: Keep-Alive
Cache-Control: no-cache
Cookie: JSESSIONID=4EF9C5B81356481F470F3C60D9E77D94

 

opt=%E4%B8%AD%E6%96%87&username=yyy&age=zzz
[End]

 

若是表單中包含須要上傳的文件數據,則在指定method="POST"的同時還要指定enctype="multipart/form-data"。以下面的表單:

[xhtml]  view plain copy
  1. <form action="checkUser.html?opt=xxx" method="POST"   
  2.         enctype="multipart/form-data">  
  3.     <input type="text" name="username" value="yyy"/>  
  4.     <input type="text" name="age" value="zzz"/>  
  5.     <input type="file" name="file" />  
  6.     <inupt type="submit" value="submit"/>  
  7. </form>  

表單提交時HTTP頭部信息以下:

POST /hello/checkUser.html?opt=xxx HTTP/1.1
Accept: */*
Referer: http://localhost:8000/hello/index.html
Accept-Language: zh-cn
Content-Type: multipart/form-data; boundary=---------------------------7d931c5d043e
Accept-Encoding: gzip, deflate
Host: localhost:8000
Content-Length: 382
Connection: Keep-Alive
Cache-Control: no-cache
Cookie: JSESSIONID=6FE3D8E365DF9FE26221A32624470D24

 

-----------------------------7d931c5d043e
Content-Disposition: form-data; name="username"

 

yyy
-----------------------------7d931c5d043e
Content-Disposition: form-data; name="age"

 

zzz
-----------------------------7d931c5d043e
Content-Disposition: form-data; name="file"; filename="C:/1.txt"
Content-Type: text/plain

 

hello
-----------------------------7d931c5d043e--

 

[End] 

GET與POST的區別

HTTP請求的GET與POST方式的本質區別能夠參考hyddd《淺談HTTP中Get與Post的區別》一文中的描述,本文講述了其中比較重要的一條,那就是數據傳輸的位置不一樣。
GET方式在request-line中傳送數據;POST方式在request-line及request-body中都可以傳送數據。

對網上傳言的解釋

傳言1:GET方式對長度有限制;POST方式對長度沒限制。
回答:長度限制之說一方面是HTTP客戶端(如IE限定URL長度爲2083字節,opera 是4050, Netscape 是8192)的限制;另外一方面服務器的實現也加入了限制(若是URL長度過長,HTTP服務器會報414錯誤)。但HTTP協議及URL官方說明均對長度限制則沒有規定。

 

傳言2:GET是從服務器上獲取數據;POST是向服務器傳送數據。
回答:GET方式就沒有向服務器傳送數據?那麼URL中的?子句送的是什麼?不管是GET仍是POST,均可以向服務器傳送數據,只不過傳送數據的位置不一樣;不管是GET仍是POST,都要從服務器上獲取數據,不然IE瀏覽器拿什麼東西給咱們看呢?關鍵的問題是
GET的主要任務是得到數據,但在得到數據前也能夠向服務器提交一些數據; 
POST的主要任務是提交數據,但在提交數據以後服務器也會向用戶端返回一些顯示用的數據。

 

傳言3:GET不安全,用戶能從地址欄上看到傳送的數據;POST安全,用戶不能從地址欄上看到傳送的數據。
回答:POST方式看不到傳送的數據是由於IE瀏覽器作了限制。若是你經過第三方工具看到了POST方式傳送的數據,你還能說POST方式是安全的嗎?理論上說GET和POST方式都不安全,要不就用不着研究HTTPS了。

參考資料:

[1]. HTTP協議(http://www.ietf.org/rfc/rfc2616.txt
[2]. HTML協議官方說明(http://www.w3.org/TR/html4/
[3]. URL標準(http://www.ietf.org/rfc/rfc1738.txt
[4]. MIME標準(http://www.ietf.org/rfc/rfc2045.txt

相關文章
相關標籤/搜索