(一)初識HTTP消息頭
但凡搞WEB開發的人都離不開HTTP(超文本傳輸協定),而要了解HTTP,除了HTML本身以外,還有一部分不可忽視的就是HTTP消息頭。
做過Socket程式設計的人都知道,當我們設計一個通信協定時,“消息頭/消息體”的分割方式是很常用的,消息頭告訴對方這個消息是幹什麼的,消息體告訴對方怎麼幹。HTTP傳輸的消息也是這樣規定的,每一個HTTP包都分為HTTP頭和HTTP體兩部分,後者是可選的,而前者是必須的。每當我們打開一個網頁,在上面點選右鍵,選擇“檢視源檔案”,這時看到的HTML代碼就是HTTP的消息體,那麼消息頭又在哪呢?IE浏覽器不讓我們看到這部分,但我們可以通過截取資料包等方法看到它。
下面就來看一個簡單的例子:
首先制作一個非常簡單的網頁,它的内容隻有一行:
<html><body>hello world</body></html>
1 解析我們輸入的位址,從中分解出協定名、主機名、端口、對象路徑等部分,對于我們的這個位址,解析得到的結果如下:
協定名:http
主機名:localhost
端口:8080
對象路徑:/simple.htm
2 把以上部分結合本機自己的資訊,封裝成一個HTTP請求資料包
3 使用TCP協定連接配接到主機的指定端口(localhost, 8080),并發送已封裝好的資料包
4 等待伺服器傳回資料,并解析傳回資料,最後顯示出來
由截取到的資料包我們不難發現浏覽器生成的HTTP資料包的内容如下:
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規定的消息頭和消息體的分界線,第一個空行以下的内容就是消息體,這個請求資料包是沒有消息體的。
消息的第一行“GET”表示我們所使用的HTTP動作,其他可能的還有“POST”等,GET的消息沒有消息體,而POST消息是有消息體的,消息體的内容就是要POST的資料。後面/simple.htm就是我們要請求的對象,之後HTTP1.1表示使用的是HTTP1.1協定。
第二行表示我們所用的浏覽器能接受的Content-type,三四兩行則是語言和編碼資訊,第五行顯示出本機的相關系資訊,包括浏覽器類型、作業系統資訊等,很多網站可以顯示出你所使用的浏覽器和作業系統版本,就是因為可以從這裡擷取到這些資訊。
第六行表示我們所請求的主機和端口,第七行表示使用Keep-Alive方式,即資料傳遞完并不立即關閉連接配接。
伺服器接收到這樣的資料包以後會根據其内容做相應的處理,例如查找有沒有“/simple.htm”這個對象,如果有,根據伺服器的設定來決定如何處理,如果是HTM,則不需要什麼複雜的處理,直接傳回其内容即可。但在直接傳回之前,還需要加上HTTP消息頭。
伺服器發回的完整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代碼。
消息頭第一行“HTTP/1.1”也是表示所使用的協定,後面的“200 OK”是HTTP傳回代碼,200就表示操作成功,還有其他常見的如404表示對象未找到,500表示伺服器錯誤,403表示不能浏覽目錄等等。
第二行表示這個伺服器使用的WEB伺服器軟體,這裡是IIS 5.1。第三行是ASP.Net的一個附加提示,沒什麼實際用處。第四行是處理此請求的時間。第五行就是所傳回的消息的content-type,浏覽器會根據它來決定如何處理消息體裡面的内容,例如這裡是text/html,那麼浏覽器就會啟用HTML解析器來處理它,如果是image/jpeg,那麼就會使用JPEG的解碼器來處理。
消息頭最後一行“Content-Length”表示消息體的長度,從空行以後的内容算起,以位元組為機關,浏覽器接收到它所指定的位元組數的内容以後就會認為這個消息已經被完整接收了。
了解HTTP消息頭 (二)
常見的HTTP傳回碼
上一篇文章裡我簡要的說了說HTTP消息頭的格式,注意到在伺服器傳回的HTTP消息頭裡有一個“HTTP/1.1 200 OK”,這裡的200是HTTP規定的傳回代碼,表示請求已經被正常處理完成。浏覽器通過這個傳回代碼就可以知道伺服器對所發請求的處理情況是什麼,每一種傳回代碼都有自己的含義。這裡列舉幾種常見的傳回碼。
1 403 Access Forbidden
如果我們試圖請求伺服器上一個檔案夾,而在WEB伺服器上這個檔案夾并沒有允許對這個檔案夾列目錄的話,就會傳回這個代碼。一個完整的403回複可能是這樣的:(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
當我們請求的對象在伺服器上并不存在時,就會給出這個傳回代碼,這可能也是最常見的錯誤代碼了。IIS給出的404消息内容很長,除了消息頭以外還有一個完整的說明“為什麼會這樣”的網頁。APACHE伺服器的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,都會在消息體内給出一個說明網頁,那麼對于用戶端來說二者有什麼差別呢?一個比較明顯的差別在于200是成功請求,浏覽器會記錄下這個位址,以便下次再通路時可以自動提示該位址,而404是失敗請求,浏覽器隻會顯示出傳回的頁面内容,并不會記錄此位址,要再次通路時還需要輸入完整的位址。
3 401 Access Denied
當WEB伺服器不允許匿名通路,而我們又沒有提供正确的使用者名/密碼時,伺服器就會給出這個傳回代碼。在IIS中,設定IIS的安全屬性為不允許匿名通路(如下圖),此時直接通路的話就會得到以下傳回結果:
HTTP/1.1 401 Access Denied
Date: Mon, 06 Mar 2006 09:15:55 GMT
WWW-Authenticate: Negotiate
WWW-Authenticate: NTLM
Content-Length: 3964
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<html dir=ltr>
……
此時浏覽器上給出的提示如下圖,讓我們輸入使用者名和密碼:
因傳回資訊中消息體較長,隻取前面兩行内容。注意,如果是用localhost來通路本機的IIS,因IE可以直接取得目前使用者的身份,它會和伺服器間直接進行協商,是以不會看到401提示。
當我們在輸入了使用者名和密碼以後,伺服器與用戶端會再進行兩次對話。首先用戶端向伺服器索取一個公鑰,伺服器端會傳回一個公鑰,二者都用BASE64編碼,相應的消息如下(編碼部分已經做了處理):
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
Authorization: Negotiate ABCDEFG……
Date: Mon, 06 Mar 2006 09:20:53 GMT
WWW-Authenticate: Negotiate HIJKLMN……
Content-Length: 3715
用戶端拿到公鑰之後使用公鑰對使用者名和密碼進行加密碼,然後把加密以後的結果重新發給伺服器:
Authorization: Negotiate OPQRST……
這樣,如果驗證通過,伺服器端就會把請求的内容發送過來了,也就是說禁止匿名通路的網站會經過三次請求才可以看到頁面。但因為用戶端浏覽器已經緩存了公鑰,用同一個浏覽器視窗再次請求這個網站上的其它頁面時就可以直接發送驗證資訊,進而一次互動就可以完成了。
4 302 Object Moved
用過ASP的人都知道ASP中頁面重定向至少有Redirect和Transfer兩種方法。二的差別在于Redirect是用戶端重定向,而Transfer是伺服器端重定向,那麼它們具體是如何通過HTTP消息頭實作的呢?
先來看一下Transfer的例子:
例如ASP檔案1.asp隻有一行
<% Server.Transfer "1.htm" %>
HTML檔案1.htm也隻有一行:
<p>this is 1.htm</p>
如果我們從浏覽器裡請求1.asp,發送的請求是:
GET /1.asp HTTP/1.1
Accept: */*
Host: localhost:8080
Cookie: ASPSESSIONIDACCTRTTT=PKKDJOPBAKMAMBNANIPIFDAP
注意請求的檔案确實是1.asp,而得到的回應則是:
HTTP/1.1 200 OK
Date: Mon, 06 Mar 2006 12:52:44 GMT
X-Powered-By: ASP.NET
Content-Length: 20
Cache-control: private
不難看出,通過Server.Transfer語句伺服器端已經做了頁面重定向,而用戶端對此一無所知,表面上看上去得到的就是1.asp的結果。
如果把1.asp的内容改為:
<% Response.Redirect "1.htm" %>
再次請求1.asp,發送的請求沒有變化,得到的回應卻變成了:
HTTP/1.1 302 Object moved
Date: Mon, 06 Mar 2006 12:55:57 GMT
Location: 1.htm
Content-Length: 121
<head><title>Object moved</title></head>
<body><h1>Object Moved</h1>This object may be found <a HREF="">here</a>.</body>
注意HTTP的傳回代碼由200變成了302,表示這是一個重定向消息,用戶端需要根據消息頭中Location字段的值重新發送請求,于是就有了下面一組對話:
GET /1.htm HTTP/1.1
If-Modified-Since: Thu, 02 Mar 2006 06:50:13 GMT
If-None-Match: "b224758ec53dc61:9f0"
Accept-Ranges: bytes
Last-Modified: Mon, 06 Mar 2006 12:52:32 GMT
ETag: "76d85bd51c41c61:9f0"
很明顯,兩種重定向方式雖然看上去結果很像,但在實作原理上有很大的不同。
5 500 Internal Server Error
500号錯誤發生在伺服器程式有錯誤的時候,例如,ASP程式為
<% if %>
顯然這個程式并不完整,于是得到的結果為:
HTTP/1.1 500 Internal Server Error
Date: Mon, 06 Mar 2006 12:58:55 GMT
Content-Length: 4301
Expires: Mon, 06 Mar 2006 12:58:55 GMT
Set-Cookie: ASPSESSIONIDACCTRTTT=ALKDJOPBPPKNPCNOEPCNOOPD; path=/
伺服器發送了500号錯誤,并且後面通過HTML的方式說明了錯誤的原因。
了解HTTP消息頭 (三)
(三) 用戶端發送的内容
這一次主要來觀察HTTP消息頭中用戶端的請求,從中找到一些有意思的内容。
1 HTTP_REFERER
寫兩個簡單的網頁:
a.htm:
<a href=b.htm>to page b</a>
b.htm:
haha
内容很簡單,就是網頁A中有一個到B的連結。把它們放到IIS上,并通路網頁A,從中再點選到B的連結,于是看到了B頁的“haha”。那麼這兩次請求有什麼不同嗎?觀察它們所發送的HTTP消息頭,最明顯的差別就是通路B頁時比通路A頁時多了一行:
這一行就表示,使用者要通路的B頁是從A頁連結過來的。
伺服器端要想取得這個值也是很容易的,以ASP為例,隻需要寫一句
<% =Request.ServerVariables("HTTP_REFERER") %>
就可以了。
一些網站通過HTTP_REFERER來做安全驗證,判斷使用者是不是從允許的頁面連結來的,而不是直接從浏覽器上打URL或從其他頁面連結過來,這樣可以從一定程度上防止網頁被做非法使用。但從上述原理來看,想要騙過伺服器也并不困難,隻要手工構造輸入的HTTP消息頭就可以了,其他常用的手段還有通過HOSTS檔案僞造域名等。
除了超連結以外,還有其他幾種方式會導緻HTTP_REFERER資訊被發送,如:
内聯架構:<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資料島:<xml src=b.asp></xml>
而以下形式不會發送HTTP_REFERER:
script轉向:<script>location.href="b.asp"</script>
script開新視窗:<script>window.open("b.asp");</script>
META轉向:<meta http-equiv="refresh" content="0;URL=b.asp">
引入圖檔:<img src=b.asp>
2 COOKIE
COOKIE是大家都非常熟悉的了,通過它可以在用戶端儲存使用者狀态,即使使用者關閉浏覽器也能繼續儲存。那麼用戶端與伺服器端是如何交換COOKIE資訊的呢?沒錯,也是通過HTTP消息頭。
首先寫一個簡單的ASP網頁:
<%
Dim i
i = Request.Cookies("key")
Response.Write i
Response.Cookies("key") = "haha"
Response.Cookies("key").Expires = #2007-1-1#
%>
第一次通路此網頁時,螢幕上一片白,第二次通路時,則會顯示出“haha”。通過閱讀程式不難發現,螢幕上顯示的内容實際上是COOKIE的内容,而第一次通路時還沒有設定COOKIE的值,是以不會有顯示,第二次顯示的是第一次設定的值。那麼對應的HTTP消息頭應該是什麼樣的呢?
第一次請求時沒什麼不同,略過
第一次傳回時消息内容多了下面這一行:
Set-Cookie: key=haha; expires=Sun, 31-Dec-2006 16:00:00 GMT; path=/
很明顯,key=haha表示鍵名為“key”的COOKIE的值為“haha”,後面是這則COOKIE的過期時間,因為我用的中文作業系統的時區是東八區,2007年1月1日0點對應的GMT時間就是2006年12月31日16點。
第二次再通路此網頁時,發送的内容多了如下一行:
Cookie: key=haha
它的内容就是剛才設的COOKIE的内容。可見,用戶端在從伺服器端得到COOKIE值以後就儲存在硬碟上,再次通路時就會把它發送到伺服器。發送時并沒有發送過期時間,因為伺服器對過期時間并不關心,當COOKIE過期後浏覽器就不會再發送它了。
如果使用IE6.0浏覽器并且禁用COOKIE功能,可以發現伺服器端的set-cookie還是有的,但用戶端并不會接受它,也不會發送它。有些網站,特别是線上投票網站通過記錄COOKIE防止使用者重複投票,破解很簡單,隻要用IE6浏覽器并禁用COOKIE就可以了。也有的網站通過COOKIE值為某值來判斷使用者是否合法,這種判斷也非常容易通過手工構造HTTP消息頭來欺騙,當然用HOSTS的方式也是可以欺騙的。
3 SESSION
HTTP協定本身是無狀态的,伺服器和用戶端都不保證使用者通路期間連接配接會一直保持,事實上保持連接配接是HTTP1.1才有的新内容,當用戶端發送的消息頭中有“Connection: Keep-Alive”時表示用戶端浏覽器支援保持連接配接的工作方式,但這個連接配接也會在一段時間沒有請求後自動斷開,以節省伺服器資源。為了在伺服器端維持使用者狀态,SESSION就被發明出來了,現在各主流的動态網頁制做工具都支援SESSION,但支援的方式不完全相同,以下皆以ASP為例。
當使用者請求一個ASP網頁時,在傳回的HTTP消息頭中會有一行:
Set-Cookie: ASPSESSIONIDCSQCRTBS=KOIPGIMBCOCBFMOBENDCAKDP; path=/
伺服器通過COOKIE的方式告訴用戶端你的SESSIONID是多少,在這裡是“KOIPGIMBCOCBFMOBENDCAKDP”,并且伺服器上保留了和此SESSIONID相關的資料,當同一使用者再次發送請求時,還會把這個COOKIE再發送回去,伺服器端根據此ID找到此使用者的資料,也就實作了伺服器端使用者狀态的儲存。是以我們用ASP程式設計時可以使用“session("name")=user”這樣的方式儲存使用者資訊。注意此COOKIE内容裡并沒有過期時間,這表示這是一個當關閉浏覽器時立即過期的COOKIE,它不會被儲存到硬碟上。這種工作方式比單純用COOKIE的方式要安全很多,因為在用戶端并沒有什麼能讓我們修改和欺騙的值,唯一的資訊就是SESSIONID,而這個ID在浏覽器關閉時會立即失效,除非别人能在你浏覽網站期間或關閉浏覽器後很短時間内知道此ID的值,才能做一些欺騙活動。因為伺服器端判斷SESSION過期的方式并不是斷開連接配接或關閉浏覽器,而是通過使用者手工結束SESSION或等待逾時,當使用者關閉浏覽器後的一段時間裡SESSION還沒有逾時,是以這時如果知道了剛才的SESSIONID,還是可以欺騙的。是以最安全的辦法還是在離開網站之前手工結束SESSION,很多網站都提供“Logout”功能,它會通過設定SESSION中的值為已退出狀态或讓SESSION立即過期進而起到安全的目的。
SESSION和COOKIE的方式各有優缺點。SESSION的優點是比較安全,不容易被欺騙,缺點是過期時間短,如果用過在超過過期時間裡沒有向伺服器發送任何資訊,就會被認為超過過期了;COOKIE則相反,根據伺服器端設定的逾時時間,可以長時間保留資訊,即使關機再開機也可能保留狀态,而安全性自然大打折扣。很多網站都提供兩種驗證方式相結合,如果使用者臨時用這台電腦通路此通路則需要輸入使用者名和密碼,不儲存COOKIE;如果使用者使用的是自己的個人電腦,則可以讓網站在自己硬碟上保留COOKIE,以後通路時就不需要重新輸入使用者名和密碼了。
4 POST
浏覽器通路伺服器常用的方式有GET和POST兩種,GET方式隻發送HTTP消息頭,沒有消息體,也就是除了要GET的基本資訊之外不向伺服器提供其他資訊,網頁表單(FROM)的預設送出方式就是用GET方式,它會把所有向伺服器送出的資訊都作為URL後面的參數,如a.asp?a=1&b=2這樣的方式。而當要送出的資料量很大,或者所送出内容不希望别人直接看到時,應該使用POST方式。POST方式送出的資料是作為HTTP消息體存在的,例如,寫一個網頁表單:
<form method=post>
<input type=text name=text1>
<input type=submit>
</form>
通路此網頁,并在表單中填入一個“haha”,然後送出,可以看到此次送出所發送的資訊如下:
POST /form.asp HTTP/1.1
Content-Type: application/x-www-form-urlencoded
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)
Content-Length: 10
Cache-Control: no-cache
Cookie: key=haha; ASPSESSIONIDCSQCRTBS=LOIPGIMBLMNOGCOBOMPJBOKP
text1=haha
前面關鍵字從“GET”變為了“POST”,Content-Type變成了“application/x-www-form-urlencoded”,後面内容并無大變化,隻是多了一行:Content-Length: 10,表示送出的内容的長度。空行後面是消息體,内容就是表單中所填的内容。注意此時發送的内容隻是“Name=Value”的形式,表單上其他的資訊不會被發送,是以想直接從伺服器端取得list box中所有的list item是辦不到的,除非在送出前用一段script把所有的item内容都連在一起放到一個隐含表單域中。
如果是用表單上傳檔案,情況就要複雜一些了,首先是表單聲明中要加上一句話:enctype='multipart/form-data',表示這個表單将送出多段資料,并用HTML:input type=file來聲明一個檔案送出域。
表單内容如下:
<form method=post enctype='multipart/form-data'>
<input type=file name=file1>
我們為text1輸入文字:hehe,為file1選擇檔案haha.txt,其内容為“ABCDEFG”,然後送出此表單。送出的完全資訊為:
Content-Type: multipart/form-data; boundary=---------------------------7d62bf2f9066c
Content-Length: 337
-----------------------------7d62bf2f9066c
Content-Disposition: form-data; name="text1"
hehe
Content-Disposition: form-data; name="file1"; filename="H:/Documents and Settings/Administrator/桌面/haha.txt"
Content-Type: text/plain
ABCDEFG
-----------------------------7d62bf2f9066c--
顯然這個送出的資訊要比前述的複雜很多。Content-Type變成了“multipart/form-data”,後面還多了一個boundary,此值是為了區分POST的内容的區段用的,隻要在内容中遇到了此值,就表示下面要開始一個新的區段了,每個區段的内容相對獨立。如果遇到的是此值後面連着兩個減号,則表示全部内容到此結束。每個段也分為段頭和段體兩部分,用空行隔開,每段都有自己的類型和相關資訊。如第一區段是text1的值,它的名稱是“text1”,值為“hehe”。第二段是檔案内容,段首裡表明了此檔案域的名稱“file1”和此檔案在使用者磁盤上的位置,後面就是檔案的内容。
如果我們想要自己寫一個上傳檔案元件來接收HTML表單傳送的檔案資料,那麼最核心的任務就是解析此資料包,從中取得需要的資訊。
了解HTTP消息頭 (四)
伺服器傳回的消息
伺服器傳回的HTTP消息也分為消息頭和消息體兩部分。前面連載的第二篇裡已經介紹了傳回消息中常見傳回代碼的含義。對于非正常的傳回代碼的處理比較簡單,隻要照着要求去做就好了,而對于正常的傳回代碼(200),其處理方式就多種多樣了。
1 Content-Type
Content-Type是傳回消息中非常重要的内容,它辨別出這個傳回内容的類型,其值為“主類型/子類型”的格式,例如最常見的就是text/html,它的意思是說傳回的内容是文本類型,這個文本又是HTML格式的。原則上浏覽器會根據Content-Type來決定如何顯示傳回的消息體内容。常見的内容類型有:
text/html HTML文本
image/jpeg JPG圖檔
image/gif GIF圖檔
application/xml XML文檔
audio/x-mpegurl MP3檔案清單,如果安裝了Winamp,則可以直接把它當面M3U檔案來打開
更多的内容類型可以在系統資料庫“HKCR/MIME/Database/Content Type”下看到
對于IE6浏覽器來說,如果Content-Type中的類型和實際的消息體類型不一緻,那麼它會根據内容中的類型來分析實際應該是什麼類型,對于JPG、GIF等常用圖檔格式都可以正确的識别出來,而不管Content-Type中寫的是什麼。
如果Content-Type中指定的是浏覽器可以直接打開的類型,那麼浏覽器就會直接打開其内容顯示出來,如果是被關聯到其它應用程式的類型,這時就要查找系統資料庫中關于這種類型的注冊情況,如果是允許直接打開而不需要詢問的,就會直接調出這個關聯的應用程式來打開這個檔案,但如果是不允許直接打開的,就會詢問是否打開。對于沒有關聯到任何應用程式的類型,IE浏覽器不知道它該如何打開,此時IE6就會把它當成XML來嘗試打開。
2 Content-Disposition
如果用AddHeader的方法在HTTP消息頭中加入Content-Disposition段,并指定其值為“attachment”,那麼無論這個檔案是何類型,浏覽器都會提示我們下載下傳此檔案,因為此時它認為後面的消息體是一個“附件”,不需要由浏覽器來處理了。例如,在ASP.Net中寫入如下語句:
Response.AddHeader("Content-Disposition: attachment");
請求此頁面是得到的結果如:
Date: Thu, 23 Mar 2006 07:54:53 GMT
Content-Disposition: attachment
Cache-Control: private
Content-Type: text/html; charset=utf-8
也就是說,通過AddHeader函數可以為HTTP消息頭加入我們自定義的内容。使用這種方法可以強制讓浏覽器提示下載下傳檔案,即使這個檔案是我們已知的類型,基于是HTML網頁。如果想要讓使用者下載下傳時提示一個預設的檔案名,隻需要在前面一句話後加上“filename=檔案名”即可。例如:
Response.AddHeader("Content-Disposition: attachment; filename=mypage.htm");
3 Content-Type與Content-Disposition
如果把Content-Type和Content-Disposition結合在一起使用會怎麼樣呢?
打開一個網頁時,浏覽器會首先看是否有Content-Disposition: attachment這一項,如果有,無論Content-Type的值是什麼,都會提示檔案下載下傳。
如果指定了filename,就會提示預設的檔案名為此檔案名。注意到在IE6中除了“儲存”按扭外還有“打開”按扭,此時打開檔案的類型是由在filename中指定的檔案擴充名決定的,例如讓filename=mypic.jpg,浏覽器就會查找預設的圖檔檢視器來打開此檔案。
如果沒有指定filename,那麼浏覽器就根據Content-Type中的類型來決定檔案的類型,例如Content-Type類型為image/gif,那麼就會去查找預設的看GIF圖檔的工具,并且設定此檔案的名字為所請求的網頁的主名(不帶擴充名)加上對應于此檔案類弄擴充名,例如請求的mypage.aspx,就會自動變成mypage.gif。如果并沒有指定Content-Type值,那麼就預設它為“text/html”,并且儲存的檔案名就是所請求的網頁檔案名。
但如果沒有指定Content-Disposition,那麼就和前面關于Content-Type中所讨論的情況是一樣的了。
4 Cache
傳回消息中的Cache用于指定網頁緩存。我們經常可以看到這樣的情況,打開一個網頁時速度不快,但再次打開時就會快很多,原因是浏覽器已經對此頁面進行了緩存,那麼在同一浏覽器視窗中再次打開此頁時不會重新從伺服器端擷取。網頁的緩存是由HTTP消息頭中的“Cache-control”來控制的,常見的取值有private、no-cache、max-age、must-revalidate等,預設為private。其作用根據不同的重新浏覽方式分為以下幾種情況:
(1) 打開新視窗
如果指定cache-control的值為private、no-cache、must-revalidate,那麼打開新視窗通路時都會重新通路伺服器。而如果指定了max-age值,那麼在此值内的時間裡就不會重新通路伺服器,例如:
Cache-control: max-age=5
表示當通路此網頁後的5秒内再次通路不會去伺服器
(2) 在位址欄回車
如果值為private或must-revalidate(和網上說的不一樣),則隻有第一次通路時會通路伺服器,以後就不再通路。如果值為no-cache,那麼每次都會通路。如果值為max-age,則在過期之前不會重複通路。
(3) 按後退按扭
如果值為private、must-revalidate、max-age,則不會重通路,而如果為no-cache,則每次都重複通路
(4) 按重新整理按扭
無論為何值,都會重複通路
當指定Cache-control值為“no-cache”時,通路此頁面不會在Internet臨時文章夾留下頁面備份。
另外,通過指定“Expires”值也會影響到緩存。例如,指定Expires值為一個早已過去的時間,那麼通路此網時若重複在位址欄按回車,那麼每次都會重複通路:
Expires: Fri, 31 Dec 1999 16:00:00 GMT
在ASP中,可以通過Response對象的Expires、ExpiresAbsolute屬性控制Expires值;通過Response對象的CacheControl屬性控制Cache-control的值,例如:
Response.ExpiresAbsolute = #2000-1-1# ' 指定絕對的過期時間,這個時間用的是伺服器當地時間,會被自動轉換為GMT時間
Response.Expires = 20 ' 指定相對的過期時間,以分鐘為機關,表示從目前時間起過多少分鐘過期。
Response.CacheControl = "no-cache"
Expires值是可以通過在Internet臨時檔案夾中檢視臨時檔案的屬性看到的,如:
HTTP請求:GET與POST方法的差別
HTTP 定義了與伺服器互動的不同方法,最基本的方法是 GET 和 POST。事實上 GET 适用于多數請求,而保留 POST 僅用于更新站點。根據 HTTP 規範,GET 用于資訊擷取,而且應該是 安全的和 幂等的。所謂安全的意味着該操作用于擷取資訊而非修改資訊。換句話說,GET 請求一般不應産生副作用。幂等的意味着對同一 URL 的多個請求應該傳回同樣的結果。完整的定義并不像看起來那樣嚴格。從根本上講,其目标是當使用者打開一個連結時,她可以确信從自身的角度來看沒有改變資源。比如,新聞站點的頭版不斷更新。雖然第二次請求會傳回不同的一批新聞,該操作仍然被認為是安全的和幂等的,因為它總是傳回目前的新聞。反之亦然。POST 請求就不那麼輕松了。POST 表示可能改變伺服器上的資源的請求。仍然以新聞站點為例,讀者對文章的注解應該通過 POST 請求實作,因為在注解送出之後站點已經不同了(比方說文章下面出現一條注解);
在FORM送出的時候,如果不指定Method,則預設為GET請求,Form中送出的資料将會附加在url之後,以?分開與url分開。字母數字字元原樣發送,但空格轉換為“+“号,其它符号轉換為%XX,其中XX為該符号以16進制表示的ASCII(或ISO Latin-1)值。GET請求請送出的資料放置在HTTP請求協定頭中,而POST送出的資料則放在實體資料中;
GET方式送出的資料最多隻能有1024位元組,而POST則沒有此限制。
HTTP 狀态碼
200 - 伺服器成功傳回網頁
404 - 請求的網頁不存在
503 - 伺服器逾時
以下是 HTTP 狀态碼的完整清單。您也可以通路 HTTP 狀态碼上的 W3C 頁以了解更多資訊。
1xx 狀态碼
表示臨時響應并需要請求者繼續執行操作的狀态碼。
100(繼續) 請求者應當繼續提出請求。伺服器傳回此代碼表示已收到請求的第一部分,正在等待其餘部分。
101(切換協定) 請求者已要求伺服器切換協定,伺服器已确認并準備切換。
2xx 狀态碼
表示成功處理了請求的狀态碼。
200(成功) 伺服器已成功處理了請求。通常,這表示伺服器提供了請求的網頁。如果針對您的 robots.txt 檔案顯示此狀态碼,則表示 Googlebot 已成功檢索到該檔案。
201(已建立) 請求成功并且伺服器建立了新的資源。
202(已接受) 伺服器已接受請求,但尚未處理。
203(非授權資訊) 伺服器已成功處理了請求,但傳回的資訊可能來自另一來源。
204(無内容) 伺服器成功處理了請求,但沒有傳回任何内容。
205(重置内容) 伺服器成功處理了請求,但沒有傳回任何内容。與 204 響應不同,此響應要求請求者重置文檔視圖(例如,清除表單内容以輸入新内容)。
206(部分内容) 伺服器成功處理了部分 GET 請求。
3xx 狀态碼
要完成請求,需要進一步操作。通常,這些狀态碼用來重定向。建議您在每次請求中使用重定向不要超過 5 次。您可以使用網站管理者工具檢視一下 Googlebot 在抓取重定向網頁時是否遇到問題。診斷下的網絡抓取頁列出了由于重定向錯誤導緻 Googlebot 無法抓取的網址。
300(多種選擇) 針對請求,伺服器可執行多種操作。伺服器可根據請求者 (user-agent) 選擇一項操作,或提供操作清單供請求者選擇。
301(永久移動) 請求的網頁已永久移動到新位置。伺服器傳回此響應(對 GET 或 HEAD 請求的響應)時,會自動将請求者轉到新位置。您應使用此代碼告訴 Googlebot 某個網頁或網站已永久移動到新位置。
302(臨時移動) 伺服器目前從不同位置的網頁響應請求,但申請人應當繼續使用原有位置來響應以後的請求。此代碼與響應 GET 和 HEAD 請求的 301 代碼類似,會自動将請求者轉到不同的位置,但不應使用此代碼來告訴 Googlebot 頁面或網站已經移動,因為 Googlebot 要繼續抓取原來的位置并編制索引。
303(檢視其他位置) 請求者應當對不同的位置使用單獨的 GET 請求來檢索響應時,伺服器傳回此代碼。對于除 HEAD 之外的所有請求,伺服器會自動轉到其他位置。
304(未修改) 自從上次請求後,請求的網頁未修改過。伺服器傳回此響應時,不會傳回網頁内容。
如果網頁自請求者上次請求後再也沒有更改過,您應當将伺服器配置為傳回此響應(稱為 If-Modified-Since HTTP 标頭)。由于伺服器可以告訴 Googlebot 自從上次抓取後網頁沒有變更,是以可節省帶寬和開銷。
305(使用代理) 請求者隻能使用代理通路請求的網頁。如果伺服器傳回此響應,還表示請求者應當使用代理。
307(臨時重定向) 伺服器目前從不同位置的網頁響應請求,但請求者應當繼續使用原有位置來響應以後的請求。此代碼與響應 GET 和 HEAD 請求的 <a href=answer.py?answer=>301</a> 代碼類似,會自動将請求者轉到不同的位置,但您不應使用此代碼來告訴 Googlebot 某個網頁或網站已經移動,因為 Googlebot 會繼續抓取原有位置并編制索引。
4xx 狀态碼
這些狀态碼表示請求可能出錯,這妨礙了伺服器的處理。
400(錯誤請求) 伺服器不了解請求的文法。
401(身份驗證錯誤) 此頁要求授權。您可能不希望将此網頁納入索引。如果您的 Sitemap 中列出該網頁,您可以将其删除。但如果您将其保留在您的 Sitemap 中,我們就不會抓取或索引該網頁(盡管該網頁将繼續保持錯誤狀态在此處列出)。如果我們将其作為搜尋抓取的一部分抓取,您可以在我們的網站管理者資訊中查閱其原因。
403(禁止) 伺服器拒絕請求。如果您在 Googlebot 嘗試抓取您網站上的有效網頁時看到此狀态碼(可以在 Google 網站管理者工具<strong>診斷</strong>下的<strong>網絡抓取< /strong>頁面上看到此資訊),可能是您的伺服器或主機拒絕 Googlebot 通路。
404(未找到) 伺服器找不到請求的網頁。例如,對于伺服器上不存在的網頁經常會傳回此代碼。
如果您的網站上沒有 robots.txt 檔案,而您在 Google 網站管理者工具"診斷"标簽的 robots.txt 頁上看到此狀态碼,那麼這是正确的狀态碼。但是,如果您有 robots.txt 檔案而又看到此狀态碼,則說明您的 robots.txt 檔案可能命名錯誤或位于錯誤的位置(該檔案應當位于頂級域,名為 robots.txt)。
如果對于 Googlebot 嘗試抓取的網址看到此狀态碼(在"診斷"标簽的 HTTP 錯誤頁面上),則表示 Googlebot 追蹤的可能是另一個頁面的無效連結(是舊連結或輸入有誤的連結)。
405(方法禁用) 禁用請求中指定的方法。
406(不接受) 無法使用請求的内容特性響應請求的網頁。
407(需要代理授權) 此狀态碼與 401 類似,但指定請求者必須授權使用代理。如果伺服器傳回此響應,還表示請求者應當使用代理。
408(請求逾時) 伺服器等候請求時發生逾時。
409(沖突) 伺服器在完成請求時發生沖突。伺服器必須在響應中包含有關沖突的資訊。伺服器在響應與前一個請求相沖突的 PUT 請求時可能會傳回此代碼,以及兩個請求的差異清單。
410(已删除) 請求的資源永久删除後,伺服器傳回此響應。該代碼與 404(未找到)代碼相似,但在資源以前存在而現在不存在的情況下,有時會用來替代 404 代碼。如果資源已永久删除,您應當使用 301 指定資源的新位置。
411(需要有效長度) 伺服器不接受不含有效内容長度标頭字段的請求。
412(未滿足前提條件) 伺服器未滿足請求者在請求中設定的其中一個前提條件。
413(請求實體過大) 伺服器無法處理請求,因為請求實體過大,超出伺服器的處理能力。
414(請求的 URI 過長) 請求的 URI(通常為網址)過長,伺服器無法處理。
415(不支援的媒體類型) 請求的格式不受請求頁面的支援。
416(請求範圍不符合要求) 如果頁面無法提供請求的範圍,則伺服器會傳回此狀态碼。
417(未滿足期望值) 伺服器未滿足"期望"請求标頭字段的要求。
5xx 狀态碼
這些狀态碼表示伺服器在處理請求時發生内部錯誤。這些錯誤可能是伺服器本身的錯誤,而不是請求出錯。
500(伺服器内部錯誤) 伺服器遇到錯誤,無法完成請求。
501(尚未實施) 伺服器不具備完成請求的功能。例如,伺服器無法識别請求方法時則會傳回此代碼。
502(錯誤網關) 伺服器作為網關或代理,從上遊伺服器收到無效響應。
503(服務不可用) 伺服器目前無法使用(由于超載或停機維護)。通常,這隻是暫時狀态。
504(網關逾時) 伺服器作為網關或代理,但是沒有及時從上遊伺服器收到請求。
505(HTTP 版本不受支援) 伺服器不支援請求中所用的 HTTP 協定版本。