理解HTTP消息頭作者:高原 日期:2006-09-13(一)初識HTTP消息頭 但凡搞WEB開發(fā)的人都離不開HTTP(超文本傳輸協(xié)議),而要了解HTTP,,除了HTML本身以外,還有一部分不可忽視的就是HTTP消息頭,。
做過Socket編程的人都知道,當(dāng)我們設(shè)計一個通信協(xié)議時,,“消息頭/消息體”的分割方式是很常用的,,消息頭告訴對方這個消息是干什么的,,消息體告訴對方怎么干。HTTP傳輸?shù)南⒁彩沁@樣規(guī)定的,,每一個HTTP包都分為HTTP頭和HTTP體兩部分,,后者是可選的,而前者是必須的,。每當(dāng)我們打開一個網(wǎng)頁,,在上面點(diǎn)擊右鍵,選擇“查看源文件”,,這時看到的HTML代碼就是HTTP的消息體,,那么消息頭又在哪呢?IE瀏覽器不讓我們看到這部分,,但我們可以通過截取數(shù)據(jù)包等方法看到它,。 下面就來看一個簡單的例子: 首先制作一個非常簡單的網(wǎng)頁,它的內(nèi)容只有一行: <html><body>hello world</body></html> 把它放到WEB服務(wù)器上,,比如IIS,,然后用IE瀏覽器請求這個頁面(http://localhost:8080/simple.htm),當(dāng)我們請求這個頁面時,,瀏覽器實(shí)際做了以下四項工作: 1 解析我們輸入的地址,從中分解出協(xié)議名,、主機(jī)名,、端口、對象路徑等部分,,對于我們的這個地址,,解析得到的結(jié)果如下: 協(xié)議名:http 主機(jī)名:localhost 端口:8080 對象路徑:/simple.htm 2 把以上部分結(jié)合本機(jī)自己的信息,封裝成一個HTTP請求數(shù)據(jù)包 3 使用TCP協(xié)議連接到主機(jī)的指定端口(localhost, 8080),,并發(fā)送已封裝好的數(shù)據(jù)包 4 等待服務(wù)器返回數(shù)據(jù),,并解析返回數(shù)據(jù),最后顯示出來 由截取到的數(shù)據(jù)包我們不難發(fā)現(xiàn)瀏覽器生成的HTTP數(shù)據(jù)包的內(nèi)容如下: GET /simple.htm HTTP/1.1<CR> Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*<CR> Accept-Language: zh-cn<CR> Accept-Encoding: gzip, deflate<CR> User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)<CR> Host: localhost:8080<CR> Connection: Keep-Alive<CR> <CR> 為了顯示清楚我把所有的回車的地方都加上了“<CR>”,,注意最后還有一個空行加一個回車,,這個空行正是HTTP規(guī)定的消息頭和消息體的分界線,第一個空行以下的內(nèi)容就是消息體,,這個請求數(shù)據(jù)包是沒有消息體的,。 消息的第一行“GET”表示我們所使用的HTTP動作,其他可能的還有“POST”等,,GET的消息沒有消息體,,而POST消息是有消息體的,消息體的內(nèi)容就是要POST的數(shù)據(jù),。后面/simple.htm就是我們要請求的對象,,之后HTTP1.1表示使用的是HTTP1.1協(xié)議,。 第二行表示我們所用的瀏覽器能接受的Content-type,三四兩行則是語言和編碼信息,,第五行顯示出本機(jī)的相關(guān)系信息,,包括瀏覽器類型、操作系統(tǒng)信息等,,很多網(wǎng)站可以顯示出你所使用的瀏覽器和操作系統(tǒng)版本,,就是因?yàn)榭梢詮倪@里獲取到這些信息。 第六行表示我們所請求的主機(jī)和端口,,第七行表示使用Keep-Alive方式,,即數(shù)據(jù)傳遞完并不立即關(guān)閉連接。 服務(wù)器接收到這樣的數(shù)據(jù)包以后會根據(jù)其內(nèi)容做相應(yīng)的處理,,例如查找有沒有“/simple.htm”這個對象,,如果有,根據(jù)服務(wù)器的設(shè)置來決定如何處理,,如果是HTM,,則不需要什么復(fù)雜的處理,直接返回其內(nèi)容即可,。但在直接返回之前,,還需要加上HTTP消息頭。 服務(wù)器發(fā)回的完整HTTP消息如下: HTTP/1.1 200 OK<CR> Server: Microsoft-IIS/5.1<CR> X-Powered-By: ASP.NET<CR> Date: Fri, 03 Mar 2006 06:34:03 GMT<CR> Content-Type: text/html<CR> Accept-Ranges: bytes<CR> Last-Modified: Fri, 03 Mar 2006 06:33:18 GMT<CR> ETag: "5ca4f75b8c3ec61:9ee"<CR> Content-Length: 37<CR> <CR> <html><body>hello world</body></html> 同樣,,我用“<CR>”來表示回車,。可以看到,,這個消息也是用空行切分成消息頭和消息體兩部分,,消息體的部分正是我們前面寫好的HTML代碼。 消息頭第一行“HTTP/1.1”也是表示所使用的協(xié)議,,后面的“200 OK”是HTTP返回代碼,,200就表示操作成功,還有其他常見的如404表示對象未找到,,500表示服務(wù)器錯誤,,403表示不能瀏覽目錄等等。 第二行表示這個服務(wù)器使用的WEB服務(wù)器軟件,,這里是IIS 5.1,。第三行是ASP.Net的一個附加提示,沒什么實(shí)際用處,。第四行是處理此請求的時間,。第五行就是所返回的消息的content-type,瀏覽器會根據(jù)它來決定如何處理消息體里面的內(nèi)容,,例如這里是text/html,,那么瀏覽器就會啟用HTML解析器來處理它,,如果是image/jpeg,那么就會使用JPEG的解碼器來處理,。 消息頭最后一行“Content-Length”表示消息體的長度,,從空行以后的內(nèi)容算起,以字節(jié)為單位,,瀏覽器接收到它所指定的字節(jié)數(shù)的內(nèi)容以后就會認(rèn)為這個消息已經(jīng)被完整接收了,。 理解HTTP消息頭 (二)常見的HTTP返回碼上一篇文章里我簡要的說了說HTTP消息頭的格式,注意到在服務(wù)器返回的HTTP消息頭里有一個“HTTP/1.1 200 OK”,,這里的200是HTTP規(guī)定的返回代碼,,表示請求已經(jīng)被正常處理完成。瀏覽器通過這個返回代碼就可以知道服務(wù)器對所發(fā)請求的處理情況是什么,,每一種返回代碼都有自己的含義,。這里列舉幾種常見的返回碼。
1 403 Access Forbidden如果我們試圖請求服務(wù)器上一個文件夾,,而在WEB服務(wù)器上這個文件夾并沒有允許對這個文件夾列目錄的話,,就會返回這個代碼。一個完整的403回復(fù)可能是這樣的:(IIS5.1)
HTTP/1.1 403 Access Forbidden Server: Microsoft-IIS/5.1 Date: Mon, 06 Mar 2006 08:57:39 GMT Connection: close Content-Type: text/html Content-Length: 172 <html><head><title>Directory Listing Denied</title></head>
<body><h1>Directory Listing Denied</h1>This Virtual Directory does not allow contents to be listed.</body></html> 2 404 Object not found當(dāng)我們請求的對象在服務(wù)器上并不存在時,,就會給出這個返回代碼,,這可能也是最常見的錯誤代碼了。IIS給出的404消息內(nèi)容很長,,除了消息頭以外還有一個完整的說明“為什么會這樣”的網(wǎng)頁,。APACHE服務(wù)器的404消息比較簡短,如下:
HTTP/1.1 404 Not Found Date: Mon, 06 Mar 2006 09:03:14 GMT Server: Apache/2.0.55 (Unix) PHP/5.0.5 Content-Length: 291 Keep-Alive: timeout=15, max=100 Connection: Keep-Alive Content-Type: text/html; charset=iso-8859-1 <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head> <title>404 Not Found</title> </head><body> <h1>Not Found</h1> <p>The requested URL /notexist was not found on this server.</p> <hr> <address>Apache/2.0.55 (Unix) PHP/5.0.5 Server at localhost Port 8080</address> </body></html> 也許你會問,,無論是404還是200,都會在消息體內(nèi)給出一個說明網(wǎng)頁,,那么對于客戶端來說二者有什么區(qū)別呢,?一個比較明顯的區(qū)別在于200是成功請求,瀏覽器會記錄下這個地址,,以便下次再訪問時可以自動提示該地址,,而404是失敗請求,瀏覽器只會顯示出返回的頁面內(nèi)容,,并不會記錄此地址,,要再次訪問時還需要輸入完整的地址。
3 401 Access Denied當(dāng)WEB服務(wù)器不允許匿名訪問,,而我們又沒有提供正確的用戶名/密碼時,,服務(wù)器就會給出這個返回代碼。在IIS中,,設(shè)置IIS的安全屬性為不允許匿名訪問(如下圖),,此時直接訪問的話就會得到以下返回結(jié)果:
HTTP/1.1 401 Access Denied Server: Microsoft-IIS/5.1 Date: Mon, 06 Mar 2006 09:15:55 GMT WWW-Authenticate: Negotiate WWW-Authenticate: NTLM Connection: close Content-Length: 3964 Content-Type: text/html <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<html dir=ltr> …… 此時瀏覽器上給出的提示如下圖,,讓我們輸入用戶名和密碼: 因返回信息中消息體較長,只取前面兩行內(nèi)容,。注意,,如果是用localhost來訪問本機(jī)的IIS,因IE可以直接取得當(dāng)前用戶的身份,,它會和服務(wù)器間直接進(jìn)行協(xié)商,,所以不會看到401提示。
當(dāng)我們在輸入了用戶名和密碼以后,,服務(wù)器與客戶端會再進(jìn)行兩次對話,。首先客戶端向服務(wù)器索取一個公鑰,服務(wù)器端會返回一個公鑰,,二者都用BASE64編碼,,相應(yīng)的消息如下(編碼部分已經(jīng)做了處理): GET / HTTP/1.1
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */* Accept-Language: zh-cn Accept-Encoding: gzip, deflate User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727) Host: 192.168.0.55:8080 Connection: Keep-Alive Authorization: Negotiate ABCDEFG…… HTTP/1.1 401 Access Denied
Server: Microsoft-IIS/5.1 Date: Mon, 06 Mar 2006 09:20:53 GMT WWW-Authenticate: Negotiate HIJKLMN…… Content-Length: 3715 Content-Type: text/html <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<html dir=ltr> …… 客戶端拿到公鑰之后使用公鑰對用戶名和密碼進(jìn)行加密碼,然后把加密以后的結(jié)果重新發(fā)給服務(wù)器: GET / HTTP/1.1 Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */* Accept-Language: zh-cn Accept-Encoding: gzip, deflate User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727) Host: 192.168.0.55:8080 Connection: Keep-Alive Authorization: Negotiate OPQRST…… 這樣,,如果驗(yàn)證通過,,服務(wù)器端就會把請求的內(nèi)容發(fā)送過來了,也就是說禁止匿名訪問的網(wǎng)站會經(jīng)過三次請求才可以看到頁面,。但因?yàn)榭蛻舳藶g覽器已經(jīng)緩存了公鑰,,用同一個瀏覽器窗口再次請求這個網(wǎng)站上的其它頁面時就可以直接發(fā)送驗(yàn)證信息,從而一次交互就可以完成了,。
4 302 Object Moved用過ASP的人都知道ASP中頁面重定向至少有Redirect和Transfer兩種方法,。二的區(qū)別在于Redirect是客戶端重定向,而Transfer是服務(wù)器端重定向,,那么它們具體是如何通過HTTP消息頭實(shí)現(xiàn)的呢,?
先來看一下Transfer的例子: 例如ASP文件1.asp只有一行 <% Server.Transfer "1.htm" %> HTML文件1.htm也只有一行: <p>this is 1.htm</p> 如果我們從瀏覽器里請求1.asp,發(fā)送的請求是: GET /1.asp HTTP/1.1 Accept: */* Accept-Language: zh-cn Accept-Encoding: gzip, deflate User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727) Host: localhost:8080 Connection: Keep-Alive Cookie: ASPSESSIONIDACCTRTTT=PKKDJOPBAKMAMBNANIPIFDAP 注意請求的文件確實(shí)是1.asp,,而得到的回應(yīng)則是:
HTTP/1.1 200 OK Server: Microsoft-IIS/5.1 Date: Mon, 06 Mar 2006 12:52:44 GMT X-Powered-By: ASP.NET Content-Length: 20 Content-Type: text/html Cache-control: private <p>this is 1.htm</p>
不難看出,,通過Server.Transfer語句服務(wù)器端已經(jīng)做了頁面重定向,而客戶端對此一無所知,,表面上看上去得到的就是1.asp的結(jié)果,。 如果把1.asp的內(nèi)容改為: <% Response.Redirect "1.htm" %> 再次請求1.asp,發(fā)送的請求沒有變化,,得到的回應(yīng)卻變成了: HTTP/1.1 302 Object moved Server: Microsoft-IIS/5.1 Date: Mon, 06 Mar 2006 12:55:57 GMT X-Powered-By: ASP.NET Location: 1.htm Content-Length: 121 Content-Type: text/html Cache-control: private <head><title>Object moved</title></head>
<body><h1>Object Moved</h1>This object may be found <a HREF="">here</a>.</body> 注意HTTP的返回代碼由200變成了302,,表示這是一個重定向消息,客戶端需要根據(jù)消息頭中Location字段的值重新發(fā)送請求,,于是就有了下面一組對話:
GET /1.htm HTTP/1.1 Accept: */* Accept-Language: zh-cn Accept-Encoding: gzip, deflate User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727) Host: localhost:8080 Connection: Keep-Alive If-Modified-Since: Thu, 02 Mar 2006 06:50:13 GMT If-None-Match: "b224758ec53dc61:9f0" Cookie: ASPSESSIONIDACCTRTTT=PKKDJOPBAKMAMBNANIPIFDAP HTTP/1.1 200 OK Server: Microsoft-IIS/5.1 X-Powered-By: ASP.NET Date: Mon, 06 Mar 2006 12:55:57 GMT Content-Type: text/html Accept-Ranges: bytes Last-Modified: Mon, 06 Mar 2006 12:52:32 GMT ETag: "76d85bd51c41c61:9f0" Content-Length: 20 <p>this is 1.htm</p>
很明顯,,兩種重定向方式雖然看上去結(jié)果很像,但在實(shí)現(xiàn)原理上有很大的不同。 5 500 Internal Server Error500號錯誤發(fā)生在服務(wù)器程序有錯誤的時候,,例如,,ASP程序?yàn)?br><% if %>
顯然這個程序并不完整,于是得到的結(jié)果為: HTTP/1.1 500 Internal Server Error Server: Microsoft-IIS/5.1 Date: Mon, 06 Mar 2006 12:58:55 GMT X-Powered-By: ASP.NET Content-Length: 4301 Content-Type: text/html Expires: Mon, 06 Mar 2006 12:58:55 GMT Set-Cookie: ASPSESSIONIDACCTRTTT=ALKDJOPBPPKNPCNOEPCNOOPD; path=/ Cache-control: private <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> <html dir=ltr>
…… 服務(wù)器發(fā)送了500號錯誤,,并且后面通過HTML的方式說明了錯誤的原因,。
理解HTTP消息頭 (三)(三) 客戶端發(fā)送的內(nèi)容 這一次主要來觀察HTTP消息頭中客戶端的請求,從中找到一些有意思的內(nèi)容,。 1 HTTP_REFERER
寫兩個簡單的網(wǎng)頁: a.htm: <a href=b.htm>to page b</a> b.htm: haha 內(nèi)容很簡單,,就是網(wǎng)頁A中有一個到B的鏈接。把它們放到IIS上,,并訪問網(wǎng)頁A,,從中再點(diǎn)擊到B的鏈接,于是看到了B頁的“haha”,。那么這兩次請求有什么不同嗎,?觀察它們所發(fā)送的HTTP消息頭,最明顯的區(qū)別就是訪問B頁時比訪問A頁時多了一行: Referer: http://localhost/a.htm 這一行就表示,,用戶要訪問的B頁是從A頁鏈接過來的,。 服務(wù)器端要想取得這個值也是很容易的,以ASP為例,,只需要寫一句 <% =Request.ServerVariables("HTTP_REFERER") %> 就可以了,。 一些網(wǎng)站通過HTTP_REFERER來做安全驗(yàn)證,判斷用戶是不是從允許的頁面鏈接來的,,而不是直接從瀏覽器上打URL或從其他頁面鏈接過來,,這樣可以從一定程度上防止網(wǎng)頁被做非法使用。但從上述原理來看,,想要騙過服務(wù)器也并不困難,,只要手工構(gòu)造輸入的HTTP消息頭就可以了,其他常用的手段還有通過HOSTS文件偽造域名等,。 除了超鏈接以外,,還有其他幾種方式會導(dǎo)致HTTP_REFERER信息被發(fā)送,如: 內(nèi)聯(lián)框架:<iframe src=b.asp></iframe> 框架集:<frameset><frame src=b.asp></frameset> 表單提交:<form action=b.asp><input type=submit></form> SCRIPT引用:<script src=b.asp></script> CSS引用:<link rel=stylesheet type=text/css href=b.asp> XML數(shù)據(jù)島:<xml src=b.asp></xml> 而以下形式不會發(fā)送HTTP_REFERER:
script轉(zhuǎn)向:<script>location.href="b.asp"</script> script開新窗口:<script>window.open("b.asp");</script> META轉(zhuǎn)向:<meta http-equiv="refresh" content="0;URL=b.asp"> 引入圖片:<img src=b.asp> 2 COOKIE
COOKIE是大家都非常熟悉的了,,通過它可以在客戶端保存用戶狀態(tài),即使用戶關(guān)閉瀏覽器也能繼續(xù)保存,。那么客戶端與服務(wù)器端是如何交換COOKIE信息的呢,?沒錯,也是通過HTTP消息頭,。 首先寫一個簡單的ASP網(wǎng)頁: <% Dim i i = Request.Cookies("key") Response.Write i Response.Cookies("key") = "haha" Response.Cookies("key").Expires = #2007-1-1# %> 第一次訪問此網(wǎng)頁時,,屏幕上一片白,第二次訪問時,則會顯示出“haha”,。通過閱讀程序不難發(fā)現(xiàn),,屏幕上顯示的內(nèi)容實(shí)際上是COOKIE的內(nèi)容,而第一次訪問時還沒有設(shè)置COOKIE的值,,所以不會有顯示,,第二次顯示的是第一次設(shè)置的值。那么對應(yīng)的HTTP消息頭應(yīng)該是什么樣的呢,? 第一次請求時沒什么不同,,略過 第一次返回時消息內(nèi)容多了下面這一行: Set-Cookie: key=haha; expires=Sun, 31-Dec-2006 16:00:00 GMT; path=/ 很明顯,key=haha表示鍵名為“key”的COOKIE的值為“haha”,,后面是這則COOKIE的過期時間,,因?yàn)槲矣玫闹形牟僮飨到y(tǒng)的時區(qū)是東八區(qū),2007年1月1日0點(diǎn)對應(yīng)的GMT時間就是2006年12月31日16點(diǎn),。 第二次再訪問此網(wǎng)頁時,,發(fā)送的內(nèi)容多了如下一行: Cookie: key=haha 它的內(nèi)容就是剛才設(shè)的COOKIE的內(nèi)容??梢?,客戶端在從服務(wù)器端得到COOKIE值以后就保存在硬盤上,再次訪問時就會把它發(fā)送到服務(wù)器,。發(fā)送時并沒有發(fā)送過期時間,,因?yàn)榉?wù)器對過期時間并不關(guān)心,當(dāng)COOKIE過期后瀏覽器就不會再發(fā)送它了,。 如果使用IE6.0瀏覽器并且禁用COOKIE功能,,可以發(fā)現(xiàn)服務(wù)器端的set-cookie還是有的,但客戶端并不會接受它,,也不會發(fā)送它,。有些網(wǎng)站,特別是在線投票網(wǎng)站通過記錄COOKIE防止用戶重復(fù)投票,,破解很簡單,,只要用IE6瀏覽器并禁用COOKIE就可以了。也有的網(wǎng)站通過COOKIE值為某值來判斷用戶是否合法,,這種判斷也非常容易通過手工構(gòu)造HTTP消息頭來欺騙,,當(dāng)然用HOSTS的方式也是可以欺騙的。 3 SESSION
HTTP協(xié)議本身是無狀態(tài)的,,服務(wù)器和客戶端都不保證用戶訪問期間連接會一直保持,,事實(shí)上保持連接是HTTP1.1才有的新內(nèi)容,當(dāng)客戶端發(fā)送的消息頭中有“Connection: Keep-Alive”時表示客戶端瀏覽器支持保持連接的工作方式,,但這個連接也會在一段時間沒有請求后自動斷開,,以節(jié)省服務(wù)器資源,。為了在服務(wù)器端維持用戶狀態(tài),SESSION就被發(fā)明出來了,,現(xiàn)在各主流的動態(tài)網(wǎng)頁制做工具都支持SESSION,,但支持的方式不完全相同,以下皆以ASP為例,。 當(dāng)用戶請求一個ASP網(wǎng)頁時,,在返回的HTTP消息頭中會有一行: Set-Cookie: ASPSESSIONIDCSQCRTBS=KOIPGIMBCOCBFMOBENDCAKDP; path=/ 服務(wù)器通過COOKIE的方式告訴客戶端你的SESSIONID是多少,在這里是“KOIPGIMBCOCBFMOBENDCAKDP”,,并且服務(wù)器上保留了和此SESSIONID相關(guān)的數(shù)據(jù),,當(dāng)同一用戶再次發(fā)送請求時,還會把這個COOKIE再發(fā)送回去,,服務(wù)器端根據(jù)此ID找到此用戶的數(shù)據(jù),,也就實(shí)現(xiàn)了服務(wù)器端用戶狀態(tài)的保存。所以我們用ASP編程時可以使用“session("name")=user”這樣的方式保存用戶信息,。注意此COOKIE內(nèi)容里并沒有過期時間,,這表示這是一個當(dāng)關(guān)閉瀏覽器時立即過期的COOKIE,它不會被保存到硬盤上,。這種工作方式比單純用COOKIE的方式要安全很多,,因?yàn)樵诳蛻舳瞬]有什么能讓我們修改和欺騙的值,唯一的信息就是SESSIONID,,而這個ID在瀏覽器關(guān)閉時會立即失效,,除非別人能在你瀏覽網(wǎng)站期間或關(guān)閉瀏覽器后很短時間內(nèi)知道此ID的值,才能做一些欺騙活動,。因?yàn)榉?wù)器端判斷SESSION過期的方式并不是斷開連接或關(guān)閉瀏覽器,,而是通過用戶手工結(jié)束SESSION或等待超時,當(dāng)用戶關(guān)閉瀏覽器后的一段時間里SESSION還沒有超時,,所以這時如果知道了剛才的SESSIONID,,還是可以欺騙的。因此最安全的辦法還是在離開網(wǎng)站之前手工結(jié)束SESSION,,很多網(wǎng)站都提供“Logout”功能,,它會通過設(shè)置SESSION中的值為已退出狀態(tài)或讓SESSION立即過期從而起到安全的目的。 SESSION和COOKIE的方式各有優(yōu)缺點(diǎn),。SESSION的優(yōu)點(diǎn)是比較安全,,不容易被欺騙,缺點(diǎn)是過期時間短,,如果用過在超過過期時間里沒有向服務(wù)器發(fā)送任何信息,,就會被認(rèn)為超過過期了;COOKIE則相反,,根據(jù)服務(wù)器端設(shè)置的超時時間,,可以長時間保留信息,即使關(guān)機(jī)再開機(jī)也可能保留狀態(tài),,而安全性自然大打折扣,。很多網(wǎng)站都提供兩種驗(yàn)證方式相結(jié)合,如果用戶臨時用這臺電腦訪問此訪問則需要輸入用戶名和密碼,,不保存COOKIE,;如果用戶使用的是自己的個人電腦,則可以讓網(wǎng)站在自己硬盤上保留COOKIE,,以后訪問時就不需要重新輸入用戶名和密碼了,。 4 POST
瀏覽器訪問服務(wù)器常用的方式有GET和POST兩種,GET方式只發(fā)送HTTP消息頭,,沒有消息體,,也就是除了要GET的基本信息之外不向服務(wù)器提供其他信息,網(wǎng)頁表單(FROM)的默認(rèn)提交方式就是用GET方式,,它會把所有向服務(wù)器提交的信息都作為URL后面的參數(shù),,如a.asp?a=1&b=2這樣的方式。而當(dāng)要提交的數(shù)據(jù)量很大,,或者所提交內(nèi)容不希望別人直接看到時,,應(yīng)該使用POST方式。POST方式提交的數(shù)據(jù)是作為HTTP消息體存在的,,例如,,寫一個網(wǎng)頁表單: <form method=post> <input type=text name=text1> <input type=submit> </form> 訪問此網(wǎng)頁,并在表單中填入一個“haha”,,然后提交,,可以看到此次提交所發(fā)送的信息如下: POST /form.asp HTTP/1.1 Accept: */* Referer: http://localhost:8080/form.asp Accept-Language: zh-cn Content-Type: application/x-www-form-urlencoded Accept-Encoding: gzip, deflate User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; InfoPath.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727) Host: localhost:8080 Content-Length: 10 Connection: Keep-Alive Cache-Control: no-cache Cookie: key=haha; ASPSESSIONIDCSQCRTBS=LOIPGIMBLMNOGCOBOMPJBOKP text1=haha
前面關(guān)鍵字從“GET”變?yōu)榱?#8220;POST”,Content-Type變成了“application/x-www-form-urlencoded”,,后面內(nèi)容并無大變化,,只是多了一行:Content-Length: 10,表示提交的內(nèi)容的長度,??招泻竺媸窍Ⅲw,內(nèi)容就是表單中所填的內(nèi)容,。注意此時發(fā)送的內(nèi)容只是“Name=Value”的形式,,表單上其他的信息不會被發(fā)送,所以想直接從服務(wù)器端取得list box中所有的list item是辦不到的,,除非在提交前用一段script把所有的item內(nèi)容都連在一起放到一個隱含表單域中,。 如果是用表單上傳文件,情況就要復(fù)雜一些了,,首先是表單聲明中要加上一句話:enctype='multipart/form-data',,表示這個表單將提交多段數(shù)據(jù),,并用HTML:input type=file來聲明一個文件提交域。 表單內(nèi)容如下: <form method=post enctype='multipart/form-data'> <input type=text name=text1> <input type=file name=file1> <input type=submit> </form> 我們?yōu)閠ext1輸入文字:hehe,,為file1選擇文件haha.txt,,其內(nèi)容為“ABCDEFG”,然后提交此表單,。提交的完全信息為: POST /form.asp HTTP/1.1 Accept: */* Referer: http://localhost:8080/form.asp Accept-Language: zh-cn Content-Type: multipart/form-data; boundary=---------------------------7d62bf2f9066c Accept-Encoding: gzip, deflate User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; InfoPath.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727) Host: localhost:8080 Content-Length: 337 Connection: Keep-Alive Cache-Control: no-cache Cookie: key=haha; ASPSESSIONIDCSQCRTBS=LOIPGIMBLMNOGCOBOMPJBOKP -----------------------------7d62bf2f9066c
Content-Disposition: form-data; name="text1" hehe
-----------------------------7d62bf2f9066c Content-Disposition: form-data; name="file1"; filename="H:\Documents and Settings\Administrator\桌面\haha.txt" Content-Type: text/plain ABCDEFG
-----------------------------7d62bf2f9066c-- 顯然這個提交的信息要比前述的復(fù)雜很多,。Content-Type變成了“multipart/form-data”,后面還多了一個boundary,,此值是為了區(qū)分POST的內(nèi)容的區(qū)段用的,,只要在內(nèi)容中遇到了此值,就表示下面要開始一個新的區(qū)段了,,每個區(qū)段的內(nèi)容相對獨(dú)立,。如果遇到的是此值后面連著兩個減號,則表示全部內(nèi)容到此結(jié)束,。每個段也分為段頭和段體兩部分,,用空行隔開,每段都有自己的類型和相關(guān)信息,。如第一區(qū)段是text1的值,,它的名稱是“text1”,值為“hehe”,。第二段是文件內(nèi)容,,段首里表明了此文件域的名稱“file1”和此文件在用戶磁盤上的位置,后面就是文件的內(nèi)容,。
如果我們想要自己寫一個上傳文件組件來接收HTML表單傳送的文件數(shù)據(jù),,那么最核心的任務(wù)就是解析此數(shù)據(jù)包,從中取得需要的信息,。 理解HTTP消息頭 (四)
|
|