spring基礎:Http請求報文

整理一些基礎知識,下面兩篇是關於http請求報文的,第一篇轉自點擊打開鏈接

HTTP請求報文解剖


HTTP請求報文由3部分組成(請求行+請求頭+請求體):



下面是一個實際的請求報文:



①是請求方法,GET和POST是最常見的HTTP方法,除此以外還包括DELETE、HEAD、OPTIONS、PUT、TRACE。不過,當前的大多數瀏覽器只支持GET和POST,Spring 3.0提供了一個HiddenHttpMethodFilter,允許你通過“_method”的表單參數指定這些特殊的HTTP方法(實際上還是通過POST提交表單)。服務端配置了HiddenHttpMethodFilter後,Spring會根據_method參數指定的值模擬出相應的HTTP方法,這樣,就可以使用這些HTTP方法對處理方法進行映射了。

②爲請求對應的URL地址,它和報文頭的Host屬性組成完整的請求URL,③是協議名稱及版本號。

④是HTTP的報文頭,報文頭包含若干個屬性,格式爲“屬性名:屬性值”,服務端據此獲取客戶端的信息。

⑤是報文體,它將一個頁面表單中的組件值通過param1=value1&param2=value2的鍵值對形式編碼成一個格式化串,它承載多個請求參數的數據。不但報文體可以傳遞請求參數,請求URL也可以通過類似於“/chapter15/user.html? param1=value1&param2=value2”的方式傳遞請求參數。

對照上面的請求報文,我們把它進一步分解,你可以看到一幅更詳細的結構圖:




引用
HttpWatch是強大的網頁數據分析工具,安裝後將集成到Internet Explorer工具欄中。它不用代理服務器或一些複雜的網絡監控工具,就能抓取請求及響應的完整信息,包括Cookies、消息頭、查詢參數、響應報文等,是Web應用開發人員的必備工具。


HTTP請求報文頭屬性

報文頭屬性是什麼東西呢?我們不妨以一個小故事來說明吧。

引用
快到中午了,張三丰不想去食堂吃飯,於是打電話叫外賣:老闆,我要一份[魚香肉絲],要12:30之前給我送過來哦,我在江湖湖公司研發部,叫張三丰。


這裏,你要[魚香肉絲]相當於HTTP報文體,而“12:30之前送過來”,你叫“張三丰”等信息就相當於HTTP的報文頭。它們是一些附屬信息,幫忙你和飯店老闆順利完成這次交易。

請求HTTP報文和響應HTTP報文都擁有若干個報文關屬性,它們是爲協助客戶端及服務端交易的一些附屬信息。


常見的HTTP請求報文頭屬性

Accept


請求報文可通過一個“Accept”報文頭屬性告訴服務端 客戶端接受什麼類型的響應。

如下報文頭相當於告訴服務端,俺客戶端能夠接受的響應類型僅爲純文本數據啊,你丫別發其它什麼圖片啊,視頻啊過來,那樣我會歇菜的~~~:

Java代碼 複製代碼 收藏代碼
  1. Accept:text/plain
Accept:text/plain


Accept屬性的值可以爲一個或多個MIME類型的值,關於MIME類型,大家請參考:http://en.wikipedia.org/wiki/MIME_type

Cookie

客戶端的Cookie就是通過這個報文頭屬性傳給服務端的哦!如下所示:
Java代碼 複製代碼 收藏代碼
  1. Cookie: $Version=1; Skin=new;jsessionid=5F4771183629C9834F8382E23BE13C4C
  Cookie: $Version=1; Skin=new;jsessionid=5F4771183629C9834F8382E23BE13C4C

服務端是怎麼知道客戶端的多個請求是隸屬於一個Session呢?注意到後臺的那個jsessionid=5F4771183629C9834F8382E23BE13C4C木有?原來就是通過HTTP請求報文頭的Cookie屬性的jsessionid的值關聯起來的!(當然也可以通過重寫URL的方式將會話ID附帶在每個URL的後面哦)。


Referer

表示這個請求是從哪個URL過來的,假如你通過google搜索出一個商家的廣告頁面,你對這個廣告頁面感興趣,鼠標一點發送一個請求報文到商家的網站,這個請求報文的Referer報文頭屬性值就是http://www.google.com。
引用

唐僧到了西天.
如來問:儂是不是從東土大唐來啊?
唐僧:厲害!你咋知道的!
如來:呵呵,我偷看了你的Referer...


很多貌似神奇的網頁監控軟件(如著名的 我要啦),只要在你的網頁上放上一段JavaScript,就可以幫你監控流量,全國訪問客戶的分佈情況等報表和圖表,其原理就是通過這個Referer及其它一些HTTP報文頭工作的。

Cache-Control

對緩存進行控制,如一個請求希望響應返回的內容在客戶端要被緩存一年,或不希望被緩存就可以通過這個報文頭達到目的。

如以下設置,相當於讓服務端將對應請求返回的響應內容不要在客戶端緩存:
Java代碼 複製代碼 收藏代碼
  1. Cache-Control: no-cache
Cache-Control: no-cache


其它請求報文頭屬性

參見:http://en.wikipedia.org/wiki/List_of_HTTP_header_fields

如何訪問請求報文頭

由於請求報文頭是客戶端發過來的,服務端當然只能讀取了,以下是HttpServletRequest一些用於讀取請求報文頭的API:

Java代碼 複製代碼 收藏代碼
  1. //獲取請求報文中的屬性名稱
  2. java.util.Enumeration<java.lang.String> getHeaderNames();
  3. //獲取指定名稱的報文頭屬性的值
  4. java.lang.String getHeader(java.lang.String name)
//獲取請求報文中的屬性名稱
java.util.Enumeration<java.lang.String>	getHeaderNames();

//獲取指定名稱的報文頭屬性的值
java.lang.String getHeader(java.lang.String name) 


由於一些請求報文頭屬性“太著名”了,因此HttpServletRequest爲它們提供了VIP的API:

Java代碼 複製代碼 收藏代碼
  1. //獲取報文頭中的Cookie(讀取Cookie的報文頭屬性)
  2. Cookie[] getCookies() ;
  3. //獲取客戶端本地化信息(讀取 Accept-Language 的報文頭屬性)
  4. java.util.Locale getLocale()
  5. //獲取請求報文體的長度(讀取Content-Length的報文頭屬性)
  6. int getContentLength();
//獲取報文頭中的Cookie(讀取Cookie的報文頭屬性)
 Cookie[]	getCookies() ;

//獲取客戶端本地化信息(讀取 Accept-Language 的報文頭屬性)
java.util.Locale	getLocale() 

//獲取請求報文體的長度(讀取Content-Length的報文頭屬性)
int getContentLength();


HttpServletRequest可以通過
Java代碼 複製代碼 收藏代碼
  1. HttpSession getSession()
HttpSession getSession() 

獲取請求所關聯的HttpSession,其內部的機理是通過讀取請求報文頭中Cookie屬性的JSESSIONID的值,在服務端的一個會話Map中,根據這個JSESSIONID獲取對應的HttpSession的對象。(這樣,你就不會覺得HttpSession很神祕了吧,你自己也可以做一個類似的會話管理

HTTP響應報文解剖

響應報文結構


HTTP的響應報文也由三部分組成(響應行+響應頭+響應體):



以下是一個實際的HTTP響應報文:



①報文協議及版本;
②狀態碼及狀態描述;
③響應報文頭,也是由多個屬性組成;
④響應報文體,即我們真正要的“乾貨”。

響應狀態碼

和請求報文相比,響應報文多了一個“響應狀態碼”,它以“清晰明確”的語言告訴客戶端本次請求的處理結果。

HTTP的響應狀態碼由5段組成:

  • 1xx 消息,一般是告訴客戶端,請求已經收到了,正在處理,別急...
  • 2xx 處理成功,一般表示:請求收悉、我明白你要的、請求已受理、已經處理完成等信息.
  • 3xx 重定向到其它地方。它讓客戶端再發起一個請求以完成整個處理。
  • 4xx 處理髮生錯誤,責任在客戶端,如客戶端的請求一個不存在的資源,客戶端未被授權,禁止訪問等。
  • 5xx 處理髮生錯誤,責任在服務端,如服務端拋出異常,路由出錯,HTTP版本不支持等。


以下是幾個常見的狀態碼:

200 OK

你最希望看到的,即處理成功!

303 See Other

我把你redirect到其它的頁面,目標的URL通過響應報文頭的Location告訴你。
引用
悟空:師傅給個桃吧,走了一天了
唐僧:我哪有桃啊!去王母娘娘那找吧


304 Not Modified

告訴客戶端,你請求的這個資源至你上次取得後,並沒有更改,你直接用你本地的緩存吧,我很忙哦,你能不能少來煩我啊!

404 Not Found

你最不希望看到的,即找不到頁面。如你在google上找到一個頁面,點擊這個鏈接返回404,表示這個頁面已經被網站刪除了,google那邊的記錄只是美好的回憶。

500 Internal Server Error

看到這個錯誤,你就應該查查服務端的日誌了,肯定拋出了一堆異常,別睡了,起來改BUG去吧!


其它的狀態碼參見:http://en.wikipedia.org/wiki/List_of_HTTP_status_codes


有些響應碼,Web應用服務器會自動給生成。你可以通過HttpServletResponse的API設置狀態碼:

Java代碼 複製代碼 收藏代碼
  1. //設置狀態碼,狀態碼在HttpServletResponse中通過一系列的常量預定義了,如SC_ACCEPTED,SC_OK
  2. void setStatus(int sc)
//設置狀態碼,狀態碼在HttpServletResponse中通過一系列的常量預定義了,如SC_ACCEPTED,SC_OK
void	setStatus(int sc) 


常見的HTTP響應報文頭屬性

Cache-Control


響應輸出到客戶端後,服務端通過該報文頭屬告訴客戶端如何控制響應內容的緩存。

下面,的設置讓客戶端對響應內容緩存3600秒,也即在3600秒內,如果客戶再次訪問該資源,直接從客戶端的緩存中返回內容給客戶,不要再從服務端獲取(當然,這個功能是靠客戶端實現的,服務端只是通過這個屬性提示客戶端“應該這麼做”,做不做,還是決定於客戶端,如果是自己宣稱支持HTTP的客戶端,則就應該這樣實現)

Java代碼 複製代碼 收藏代碼
  1. Cache-Control: max-age=3600
Cache-Control: max-age=3600


ETag

一個代表響應服務端資源(如頁面)版本的報文頭屬性,如果某個服務端資源發生變化了,這個ETag就會相應發生變化。它是Cache-Control的有益補充,可以讓客戶端“更智能”地處理什麼時候要從服務端取資源,什麼時候可以直接從緩存中返回響應。

關於ETag的說明,你可以參見:http://en.wikipedia.org/wiki/HTTP_ETag
Spring 3.0還專門爲此提供了一個org.springframework.web.filter.ShallowEtagHeaderFilter(實現原理很簡單,對JSP輸出的內容MD5,這樣內容有變化ETag就相應變化了),用於生成響應的ETag,因爲這東東確實可以幫助減少請求和響應的交互。

下面是一個ETag:
Java代碼 複製代碼 收藏代碼
  1. ETag: "737060cd8c284d8af7ad3082f209582d"
ETag: "737060cd8c284d8af7ad3082f209582d"


Location

我們在JSP中讓頁面Redirect到一個某個A頁面中,其實是讓客戶端再發一個請求到A頁面,這個需要Redirect到的A頁面的URL,其實就是通過響應報文頭的Location屬性告知客戶端的,如下的報文頭屬性,將使客戶端redirect到iteye的首頁中:

Java代碼 複製代碼 收藏代碼
  1. Location: http://www.iteye.com
Location: http://www.iteye.com


Set-Cookie

服務端可以設置客戶端的Cookie,其原理就是通過這個響應報文頭屬性實現的:

Java代碼 複製代碼 收藏代碼
  1. Set-Cookie: UserID=JohnDoe; Max-Age=3600; Version=1
Set-Cookie: UserID=JohnDoe; Max-Age=3600; Version=1



其它HTTP響應報文頭屬性

更多其它的HTTP響應頭報文,參見:http://en.wikipedia.org/wiki/List_of_HTTP_header_fields


如何寫HTTP請求報文頭

在服務端可以通過HttpServletResponse的API寫響應報文頭的屬性:

Java代碼 複製代碼 收藏代碼
  1. //添加一個響應報文頭屬性
  2. void setHeader(String name, String value)
//添加一個響應報文頭屬性
void	setHeader(String name, String value) 


象Cookie,Location這些響應都是有福之人,HttpServletResponse爲它們都提供了VIP版的API:
Java代碼 複製代碼 收藏代碼
  1. //添加Cookie報文頭屬性
  2. void addCookie(Cookie cookie)
  3. //不但會設置Location的響應報文頭,還會生成303的狀態碼呢,兩者天仙配呢
  4. void sendRedirect(String location)
//添加Cookie報文頭屬性
void addCookie(Cookie cookie) 

//不但會設置Location的響應報文頭,還會生成303的狀態碼呢,兩者天仙配呢
void	sendRedirect(String location) 
以下轉自:淺談HTTP中Get與Post的區別

淺談HTTP中Get與Post的區別

2009-03-31 14:51 by hyddd, 286669 閱讀, 76 評論, 收藏編輯

  Http定義了與服務器交互的不同方法,最基本的方法有4種,分別是GET,POST,PUT,DELETE。URL全稱是資源描述符,我們可以這樣認爲:一個URL地址,它用於描述一個網絡上的資源,而HTTP中的GET,POST,PUT,DELETE就對應着對這個資源的4個操作。到這裏,大家應該有個大概的瞭解了,GET一般用於獲取/查詢資源信息,而POST一般用於更新資源信息。

  1.根據HTTP規範,GET用於信息獲取,而且應該是安全的和冪等的

  (1).所謂安全的意味着該操作用於獲取信息而非修改信息。換句話說,GET 請求一般不應產生副作用。就是說,它僅僅是獲取資源信息,就像數據庫查詢一樣,不會修改,增加數據,不會影響資源的狀態。

  * 注意:這裏安全的含義僅僅是指是非修改信息。

  (2).冪等的意味着對同一URL的多個請求應該返回同樣的結果。這裏我再解釋一下冪等這個概念:

複製代碼
  冪等(idempotent、idempotence)是一個數學或計算機學概念,常見於抽象代數中。
  冪等有一下幾種定義:
  對於單目運算,如果一個運算對於在範圍內的所有的一個數多次進行該運算所得的結果和進行一次該運算所得的結果是一樣的,那麼我們就稱該運算是冪等的。比如絕對值運算就是一個例子,在實數集中,有abs(a)
=abs(abs(a))
  對於雙目運算,則要求當參與運算的兩個值是等值的情況下,如果滿足運算結果與參與運算的兩個值相等,則稱該運算冪等,如求兩個數的最大值的函數,有在在實數集中冪等,即max(x,x) 
= x
複製代碼

看完上述解釋後,應該可以理解GET冪等的含義了。

  但在實際應用中,以上2條規定並沒有這麼嚴格。引用別人文章的例子:比如,新聞站點的頭版不斷更新。雖然第二次請求會返回不同的一批新聞,該操作仍然被認爲是安全的和冪等的,因爲它總是返回當前的新聞。從根本上說,如果目標是當用戶打開一個鏈接時,他可以確信從自身的角度來看沒有改變資源即可。

  2.根據HTTP規範,POST表示可能修改變服務器上的資源的請求。繼續引用上面的例子:還是新聞以網站爲例,讀者對新聞發表自己的評論應該通過POST實現,因爲在評論提交後站點的資源已經不同了,或者說資源被修改了。

 

  上面大概說了一下HTTP規範中GET和POST的一些原理性的問題。但在實際的做的時候,很多人卻沒有按照HTTP規範去做,導致這個問題的原因有很多,比如說:

  1.很多人貪方便,更新資源時用了GET,因爲用POST必須要到FORM(表單),這樣會麻煩一點。

  2.對資源的增,刪,改,查操作,其實都可以通過GET/POST完成,不需要用到PUT和DELETE。

  3.另外一個是,早期的Web MVC框架設計者們並沒有有意識地將URL當作抽象的資源來看待和設計,所以導致一個比較嚴重的問題是傳統的Web MVC框架基本上都只支持GET和POST兩種HTTP方法,而不支持PUT和DELETE方法。

   * 簡單解釋一下MVC:MVC本來是存在於Desktop程序中的,M是指數據模型,V是指用戶界面,C則是控制器。使用MVC的目的是將M和V的實現代碼分離,從而使同一個程序可以使用不同的表現形式。

  以上3點典型地描述了老一套的風格(沒有嚴格遵守HTTP規範),隨着架構的發展,現在出現REST(Representational State Transfer),一套支持HTTP規範的新風格,這裏不多說了,可以參考《RESTful Web Services》。

 

  說完原理性的問題,我們再從表面現像上面看看GET和POST的區別

  1.GET請求的數據會附在URL之後(就是把數據放置在HTTP協議頭中),以?分割URL和傳輸數據,參數之間以&相連,如:login.action?name=hyddd&password=idontknow&verify=%E4%BD%A0%E5%A5%BD。如果數據是英文字母/數字,原樣發送,如果是空格,轉換爲+,如果是中文/其他字符,則直接把字符串用BASE64加密,得出如:%E4%BD%A0%E5%A5%BD,其中%XX中的XX爲該符號以16進製表示的ASCII。

  POST把提交的數據則放置在是HTTP包的包體中。

  2."GET方式提交的數據最多隻能是1024字節,理論上POST沒有限制,可傳較大量的數據,IIS4中最大爲80KB,IIS5中爲100KB"??!

  以上這句是我從其他文章轉過來的,其實這樣說是錯誤的,不準確的:

  (1).首先是"GET方式提交的數據最多隻能是1024字節",因爲GET是通過URL提交數據,那麼GET可提交的數據量就跟URL的長度有直接關係了。而實際上,URL不存在參數上限的問題HTTP協議規範沒有對URL長度進行限制。這個限制是特定的瀏覽器及服務器對它的限制。IE對URL長度的限制是2083字節(2K+35)。對於其他瀏覽器,如Netscape、FireFox等,理論上沒有長度限制,其限制取決於操作系統的支持。

  注意這是限制是整個URL長度,而不僅僅是你的參數值數據長度。[見參考資料5]

  (2).理論上講,POST是沒有大小限制的HTTP協議規範也沒有進行大小限制,說“POST數據量存在80K/100K的大小限制”是不準確的,POST數據是沒有限制的,起限制作用的是服務器的處理程序的處理能力。

  對於ASP程序,Request對象處理每個表單域時存在100K的數據長度限制。但如果使用Request.BinaryRead則沒有這個限制。

  由這個延伸出去,對於IIS 6.0,微軟出於安全考慮,加大了限制。我們還需要注意:

     1).IIS 6.0默認ASP POST數據量最大爲200KB,每個表單域限制是100KB。
     2).IIS 6.0默認上傳文件的最大大小是4MB。
     3).IIS 6.0默認最大請求頭是16KB。
  IIS 6.0之前沒有這些限制。[見參考資料5]

  所以上面的80K,100K可能只是默認值而已(注:關於IIS4和IIS5的參數,我還沒有確認),但肯定是可以自己設置的。由於每個版本的IIS對這些參數的默認值都不一樣,具體請參考相關的IIS配置文檔。

  3.在ASP中,服務端獲取GET請求參數用Request.QueryString,獲取POST請求參數用Request.Form。在JSP中,用request.getParameter(\"XXXX\")來獲取,雖然jsp中也有request.getQueryString()方法,但使用起來比較麻煩,比如:傳一個test.jsp?name=hyddd&password=hyddd,用request.getQueryString()得到的是:name=hyddd&password=hyddd。在PHP中,可以用$_GET和$_POST分別獲取GET和POST中的數據,而$_REQUEST則可以獲取GET和POST兩種請求中的數據。值得注意的是,JSP中使用request和PHP中使用$_REQUEST都會有隱患,這個下次再寫個文章總結。

  4.POST的安全性要比GET的安全性高。注意:這裏所說的安全性和上面GET提到的“安全”不是同個概念。上面“安全”的含義僅僅是不作數據修改,而這裏安全的含義是真正的Security的含義,比如:通過GET提交數據,用戶名和密碼將明文出現在URL上,因爲(1)登錄頁面有可能被瀏覽器緩存,(2)其他人查看瀏覽器的歷史紀錄,那麼別人就可以拿到你的賬號和密碼了,除此之外,使用GET提交數據還可能會造成Cross-site request forgery攻擊。

  總結一下,Get是向服務器發索取數據的一種請求,而Post是向服務器提交數據的一種請求,在FORM(表單)中,Method默認爲"GET",實質上,GET和POST只是發送機制不同,並不是一個取一個發!

  純屬hyddd個人總結,如有錯漏請指出。:>

 

參考資料

[1].http://hi.baidu.com/liuzd003/blog/item/7bfecbfa6ea94ed8b58f318c.html

[2].http://www.blogjava.net/onlykeke/archive/2006/08/23/65285.aspx

[3].http://baike.baidu.com/view/2067025.htm

[4].http://www.chxwei.com/article.asp?id=373

[5].http://blog.csdn.net/somat/archive/2004/10/29/158707.aspx

轉載請說明出處,謝謝[hyddd(http://www.cnblogs.com/hyddd/)]

 


發佈了14 篇原創文章 · 獲贊 13 · 訪問量 10萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章