做者:darxin html
HTTP的GET/POST方式有何區別?這是一個老生常談的問題,但老生常談的問題每每有一些讓人誤解的結論。本文將帶您淺嘗HTTP協議,在瞭解HTTP協議的同時將會展現許多被人們忽視的內容。在掌握了HTTP協議的過程當中咱們將天然而然地瞭解到GET與POST的本質區別。 瀏覽器
從使用者的角度看,一個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表單的使用方法以下:
表單中存在各類類型的表單域標籤,如<input/>、<textarea/>及<select/>。每一種表單域標籤均有NAME與VALUE兩種標籤屬性。這兩個標籤屬性決定了表單提交時傳送的屬性名及相應的值。
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編碼規則。以下面的表單:
這樣的表單是不符合要求的。若是其URL值存在非法字符(如中文字符),應將其進行URL Encoding處理。URL Encoding的處理方法以下:
將「中文」兩個字符進行URL Encoding所獲得的值就是「%E4%B8%AD%E6%96%87」。
因此正確的表單應該是:
method標籤屬性指定了表單的發送方式,發送方式只有兩種:GET及POST。
當以GET方式發送表單時,發送的HTTP請求沒有request-body部分,因此不須要指定enctype標籤屬性。
GET方式只提交表單域中的數據,action標籤屬性中若是存在?子句,GET方式將不予處理。以下面的表單:
表單提交時沒有包括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處理。這個操做一般是由用戶端瀏覽器完成的。以下面的表單:
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中得以保留。以下面的表單:
表單提交時,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中的非法字符。以下面的表單是不符合要求的:
正確的表單應該是:
在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處理。以下面的表單:
表單提交時,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"。以下面的表單:
表單提交時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]
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)