十二月 3rd, 2009歸檔于:文摘翻譯讀
書筆記Tag: Internet, web 非常感謝 @ytzong同學(xué)在twitter上推薦這篇文章,原文在此。 本文系統(tǒng)的對(duì)HTTP Headers進(jìn)行了簡(jiǎn)明易懂的闡述,,我僅稍作筆記,。 什么是HTTP HeadersHTTP是“Hypertext Transfer Protocol”的所寫,整個(gè)萬維網(wǎng)都在使用這種協(xié)議,,幾乎你在瀏覽器里看到的大部分內(nèi)容都是通過http協(xié)議來傳輸?shù)?,比如這篇文章。 HTTP Headers是HTTP請(qǐng)求和相應(yīng)的核心,,它承載了關(guān)于客戶端瀏覽器,,請(qǐng)求頁(yè)面,服務(wù)器等相關(guān)的信息,。 示例當(dāng)你在瀏覽器地址欄里鍵入一個(gè)url,,你的瀏覽器將會(huì)類似如下的http請(qǐng)求: 請(qǐng)求完成之后,,你的瀏覽器可能會(huì)收到如下的HTTP響應(yīng):
第一行呢被稱為“Status Line”,,它之后就是http headers,,空行完了就開始輸出內(nèi)容了(在這個(gè)案例中是一些html輸出),。 但你查看頁(yè)面源代碼卻不能看到HTTP headers,,雖然它們同你能看到的東西一起被傳送至瀏覽器了。 這個(gè)HTTP請(qǐng)求也發(fā)出了一些其它資源的接收請(qǐng)求,,例如圖片,,css文件,js文件等等,。 下面我們來看看細(xì)節(jié),。 怎樣才能看到HTTP Headers下面這些FireFox擴(kuò)展能夠幫助你分析HTTP headers: 1. firebug 3. 在PHP中:
文章下面將會(huì)看到一些使用php示范的例子。 HTTP Request 的結(jié)構(gòu)被稱作“first line”的第一行包含三個(gè)部分:
剩下的部分每行都是一個(gè)“Name:Value”對(duì),。它們包含了各式各樣關(guān)于請(qǐng)求和你瀏覽器的信息。例如”User-Agent“就表明了你瀏覽器 版本和你所用的操作系統(tǒng),?!盇ccept-Encoding“會(huì)告訴服務(wù)器你的瀏覽可以接受類似gzip的壓縮輸出。 這些headers大部分都是可選的,。HTTP 請(qǐng)求甚至可以被精簡(jiǎn)成這樣子:
并且你仍舊可以從服務(wù)器收到有效的響應(yīng),。 請(qǐng)求類型三種最常見的請(qǐng)求類型是:GET,POST 和 HEAD ,,從html的編寫過程中你可能已經(jīng)熟悉了前兩種,。 GET:獲取一個(gè)文檔大部分被傳輸?shù)綖g覽器的html,images,,js,,css, … 都是通過GET方法發(fā)出請(qǐng)求的。它是獲取數(shù)據(jù)的主要方法,。 例如,,要獲取Nettuts+ 的文章,,http request的第一行通常看起來是這樣的:
一旦html加載完成,,瀏覽器將會(huì)發(fā)送GET 請(qǐng)求去獲取圖片,,就像下面這樣:
表單也可以通過GET方法發(fā)送,下面是個(gè)例子:
當(dāng)這個(gè)表單被提交時(shí),,HTTP request 就會(huì)像這樣:
你可以將表單輸入通過附加進(jìn)查詢字符串的方式發(fā)送至服務(wù)器,。 POST:發(fā)送數(shù)據(jù)至服務(wù)器盡管你可以通過GET方法將數(shù)據(jù)附加到url中傳送給服務(wù)器,但在很多情況下使用POST發(fā)送數(shù)據(jù)給服務(wù)器更加合適,。通過GET發(fā)送大量數(shù)據(jù)是不現(xiàn) 實(shí)的,,它有一定的局限性。 用POST請(qǐng)求來發(fā)送表單數(shù)據(jù)是普遍的做法,。我們來吧上面的例子改造成使用POST方式:
提交這個(gè)表單會(huì)創(chuàng)建一個(gè)如下的HTTP 請(qǐng)求:
這里有三個(gè)需要注意的地方:
POST方式的請(qǐng)求也可用在AJAX,,應(yīng)用程序,cURL … 之上,。并且所有的文件上傳表單都被要求使用POST方式,。 HEAD:接收頭部信息HEAD和GET很相似,只不過HEAD不接受HTTP響應(yīng)的內(nèi)容部分,。當(dāng)你發(fā)送了一個(gè)HEAD請(qǐng)求,,那就意味著你只對(duì)HTTP頭部感興趣,而不是 文檔本身,。 這個(gè)方法可以讓瀏覽器判斷頁(yè)面是否被修改過,,從而控制緩存。也可判斷所請(qǐng)求的文檔是否存在,。 例如,,假如你的網(wǎng)站上有很多鏈接,那么你就可以簡(jiǎn)單的給他們分別發(fā)送HEAD請(qǐng)求來判斷是否存在死鏈,,這比使用GET要快很多,。 http響應(yīng)結(jié)構(gòu)當(dāng)瀏覽器發(fā)送了HTTP請(qǐng)求之后,服務(wù)器就會(huì)通過一個(gè)HTTP response來響應(yīng)這個(gè)請(qǐng)求,。如果不關(guān)心內(nèi)容,,那么這個(gè)請(qǐng)求看起來會(huì)是這樣的: 第一個(gè)有價(jià)值的信息就是協(xié)議。目前服務(wù)器都會(huì)使用 HTTP/1.x 或者 HTTP/1.1,。 接下來一個(gè)簡(jiǎn)短的信息代表狀態(tài),。代碼200意味著我們的請(qǐng)求已經(jīng)發(fā)送成功了,服務(wù)器將會(huì)返回給我們所請(qǐng)求的文檔,,在頭部信息之后,。 我們都見過“404”頁(yè)面,。當(dāng)我向服務(wù)器請(qǐng)求一個(gè)不存在的路徑時(shí),服務(wù)器就用用404來代替200響應(yīng)我們,。 余下的響應(yīng)內(nèi)容和HTTP請(qǐng)求相似,。這些內(nèi)容是關(guān)于服務(wù)器軟件的,頁(yè)面/文件何時(shí)被修改過,,mime type 等等… 同樣,,這些頭部信息也是可選的。 HTTP狀態(tài)碼
200 成功 (OK) 前文已經(jīng)提到,,200是用來表示請(qǐng)求成功的,。 206 部分內(nèi)容 (Partial Content) 如果一個(gè)應(yīng)用只請(qǐng)求某范圍之內(nèi)的文件,那么就會(huì)返回206. 這通常被用來進(jìn)行下載管理,,斷點(diǎn)續(xù)傳或者文件分塊下載,。 404 沒有找到 (Not Found) 很容易理解 401 未經(jīng)授權(quán) (Unauthorized) 受密碼保護(hù)的頁(yè)面會(huì)返回這個(gè)狀態(tài)。如果你沒有輸入正確的密碼,,那么你就會(huì)在瀏覽器中看到如下的信息: 注意這只是受密碼保護(hù)頁(yè)面,,請(qǐng)求輸入密碼的彈出框是下面這個(gè)樣子的: 403 被禁止(Forbidden) 如果你沒有權(quán)限訪問某個(gè)頁(yè)面,,那么就會(huì)返回403狀態(tài),。這種情況通常會(huì)發(fā)生在你試圖打開一個(gè)沒有index頁(yè)面的文件夾。如果服務(wù)器設(shè)置不允許查看 目錄內(nèi)容,,那么你就會(huì)看到403錯(cuò)誤,。 其它一些一些方式也會(huì)發(fā)送權(quán)限限制,例如你可以通過IP地址進(jìn)行阻止,,這需要一些htaccess的協(xié)助,。
302(或307)臨時(shí)移動(dòng)(Moved Temporarily) 和 301 永久移動(dòng)(Moved Permanently) 這兩個(gè)狀態(tài)會(huì)出現(xiàn)在瀏覽器重定向時(shí)。例如,,你使用了類似 bit.ly 的網(wǎng)址縮短服務(wù),。這也是它們?nèi)绾潍@知誰點(diǎn)擊了他們鏈接的方法。 302和301對(duì)于瀏覽器來說是非常相似的,,但對(duì)于搜索引擎爬蟲就有一些差別,。打個(gè)比方,如果你的網(wǎng)站正在維護(hù),,那么你就會(huì)將客戶端瀏覽器用302 重定向到另外一個(gè)地址,。搜索引擎爬蟲就會(huì)在將來重新索引你的頁(yè)面。但是如果你使用了301重定向,,這就等于你告訴了搜索引擎爬蟲:你的網(wǎng)站已經(jīng)永久的移動(dòng) 到了新的地址,。 500 服務(wù)器錯(cuò)誤(Internal Server Error) 這個(gè)代碼通常會(huì)在頁(yè)面腳本崩潰時(shí)出現(xiàn)。大部分CGI腳本都不會(huì)像PHP那樣輸出錯(cuò)誤信息給瀏覽器,。如果出現(xiàn)了致命的錯(cuò)誤,,它們只會(huì)發(fā)送一個(gè)500的 狀態(tài)碼,。這時(shí)需要查看服務(wù)器錯(cuò)誤日志來排錯(cuò)。 完整的列表 你可以在這里找到完整的HTTP 狀態(tài)碼說明,。 HTTP Headers 中的 HTTP請(qǐng)求現(xiàn)在我們來看一些在HTTP headers中常見的HTTP請(qǐng)求信息,。 所有這些頭部信息都可以在PHP的$_SERVER數(shù)組中找到。你也可以用getallheaders()函數(shù)一次性獲取所有的頭部信息,。 Host一個(gè)HTTP請(qǐng)求會(huì)發(fā)送至一個(gè)特定的IP地址,,但是大部分服務(wù)器都有在同一IP地址下托管多個(gè)網(wǎng)站的能力,那么服務(wù)器必須知道瀏覽器請(qǐng)求的是哪個(gè)域 名下的資源,。
這只是基本的主機(jī)名,,包含域名和子級(jí)域名。 在PHP中,,可以通過$_SERVER['HTTP_HOST'] 或 $_SERVER['SERVER_NAME']來查看,。 User-Agent
這個(gè)頭部可以攜帶如下幾條信息:
這就是某些網(wǎng)站用來收集訪客信息的一般手段。例如,,你可以判斷訪客是否在使用手機(jī)訪問你的網(wǎng)站,,然后決定是否將他們引導(dǎo)至一個(gè)在低分辨率下表現(xiàn)良好 的移動(dòng)網(wǎng)站。 在PHP中,,可以通過 $_SERVER['HTTP_USER_AGENT'] 來獲取User-Agent
Accept-Language
這個(gè)信息可以說明用戶的默認(rèn)語言設(shè)置,。如果網(wǎng)站有不同的語言版本,那么就可以通過這個(gè)信息來重定向用戶的瀏覽器,。 它可以通過逗號(hào)分割來攜帶多國(guó)語言,。第一個(gè)會(huì)是首選的語言,其它語言會(huì)攜帶一個(gè)“q”值,,來表示用戶對(duì)該語言的喜好程度(0~1),。 在PHP中用 $_SERVER["HTTP_ACCEPT_LANGUAGE"] 來獲取這一信息。
Accept-Encoding
大部分的現(xiàn)代瀏覽器都支持gzip壓縮,,并會(huì)把這一信息報(bào)告給服務(wù)器,。這時(shí)服務(wù)器就會(huì)壓縮過的HTML發(fā)送給瀏覽器。這可以減少近80%的文件大 小,,以節(jié)省下載時(shí)間和帶寬,。 在PHP中可以使用 $_SERVER["HTTP_ACCEPT_ENCODING"] 獲取該信息。 然后調(diào)用ob_gzhandler()方 法時(shí)會(huì)自動(dòng)檢測(cè)該值,,所以你無需手動(dòng)檢測(cè),。
If-Modified-Since如果一個(gè)頁(yè)面已經(jīng)在你的瀏覽器中被緩存,那么你下次瀏覽時(shí)瀏覽器將會(huì)檢測(cè)文檔是否被修改過,,那么它就會(huì)發(fā)送這樣的頭部:
如果自從這個(gè)時(shí)間以來未被修改過,,那么服務(wù)器將會(huì)返回“304 Not Modified”,而且不會(huì)再返回內(nèi)容,。瀏覽器將自動(dòng)去緩存中讀取內(nèi)容 在PHP中,,可以用$_SERVER['HTTP_IF_MODIFIED_SINCE'] 來檢測(cè)。
還有一個(gè)叫Etag的HTTP頭信息,,它被用來確定緩存的信息是否正確,,稍后我們將會(huì)解釋它。 Cookie顧名思義,,他會(huì)發(fā)送你瀏覽器中存儲(chǔ)的Cookie信息給服務(wù)器,。
它是用分號(hào)分割的一組名值對(duì)。Cookie也可以包含session id,。 在PHP中,,單一的Cookie可以訪問$_COOKIE數(shù)組獲得。你可以直接用$_SESSION array獲取session變量,。如果你需要session id,那么你可以使用session_id()函數(shù)代替cookie,。
Referer顧名思義, 頭部將會(huì)包含referring url信息。 例如,,我訪問Nettuts+的主頁(yè)并點(diǎn)擊了一個(gè)鏈接,,這個(gè)頭部信息將會(huì)發(fā)送到瀏覽器: 在PHP中,,可以通過 $_SERVER['HTTP_REFERER'] 獲取該值,。
You may have noticed the word “referrer” is misspelled as “referer”. Unfortunately it made into the official HTTP specifications like that and got stuck. Authorization當(dāng)一個(gè)頁(yè)面需要授權(quán),瀏覽器就會(huì)彈出一個(gè)登陸窗口,,輸入正確的賬號(hào)后,,瀏覽器會(huì)發(fā)送一個(gè)HTTP請(qǐng)求,但此時(shí)會(huì)包含這樣一個(gè)頭部:
包含在頭部的這部分信息是base64 encoded,。例如,base64_decode(’bXl1c2VyOm15cGFzcw==’) 會(huì)被轉(zhuǎn)化為 ‘myuser:mypass’ ,。 在PHP中,,這個(gè)值可以用$_SERVER['PHP_AUTH_USER'] 和 $_SERVER['PHP_AUTH_PW'] 獲得。 更多細(xì)節(jié)我們會(huì)在WWW-Authenticate部分講解,。 HTTP Headers 中的 HTTP響應(yīng)現(xiàn)在讓我了解一些常見的HTTP Headers中的HTTP響應(yīng)信息,。 在PHP中,你可以通過 header()來設(shè)置頭部響應(yīng)信息,。PHP已經(jīng)自動(dòng)發(fā)送了一些必要的頭部信息,,如 載入的內(nèi)容,,設(shè)置 cookies 等等… 你可以通過 headers_list()函數(shù)看到已發(fā)送和將要發(fā)送的頭部信息。你也可以使用headers_sent()函 數(shù)來檢查頭部信息是否已經(jīng)被發(fā)送,。 Cache-Control的定義是:“The Cache-Control general-header field is used to specify directives which MUST be obeyed by all caching mechanisms along the request/response chain.” 其中“caching mechanisms” 包含一些你ISP可能會(huì)用到的 網(wǎng)關(guān)和代理信息,。 例如:
“public”意味著這個(gè)響應(yīng)可以被任何人緩存,“max-age” 則表明了該緩存有效的秒數(shù),。允許你的網(wǎng)站被緩存降大大減少下載時(shí)間和帶寬,,同時(shí)也提高的瀏覽器的載入速度。 也可以通過設(shè)置 “no-cache” 指令來禁止緩存:
Content-Type這個(gè)頭部包含了文檔的”mime-type”,。瀏覽器將會(huì)依據(jù)該參數(shù)決定如何對(duì)文檔進(jìn)行解析。例如,,一個(gè)html頁(yè)面(或者有html輸出的php 頁(yè)面)將會(huì)返回這樣的東西:
‘text’ 是文檔類型,,‘html’則是文檔子類型。 這個(gè)頭部還包括了更多信息,,例如 charset,。 如果是一個(gè)圖片,將會(huì)發(fā)送這樣的響應(yīng):
瀏覽器可以通過mime-type來決定使用外部程序還是自身擴(kuò)展來打開該文檔,。如下的例子降調(diào)用Adobe Reader:
直接載入,,Apache通常會(huì)自動(dòng)判斷文檔的mime-type并且添加合適的信息到頭部去。并且大部分瀏覽器都有一定程度的容錯(cuò),,在頭部未提供或 者錯(cuò)誤提供該信息的情況下它會(huì)去自動(dòng)檢測(cè)mime-type,。 你可以在這里找到一個(gè)常用mime-type列表。 在PHP中你可以通過 finfo_file()來檢測(cè)文件的ime-type,。 Content-Disposition這個(gè)頭部信息將告訴瀏覽器打開一個(gè)文件下載窗口,,而不是試圖解析該響應(yīng)的內(nèi)容。例如:
他會(huì)導(dǎo)致瀏覽器出現(xiàn)這樣的對(duì)話框: 注意,,適合它的Content-Type頭信息同時(shí)也會(huì)被發(fā)送
Content-Length當(dāng)內(nèi)容將要被傳輸?shù)綖g覽器時(shí),,服務(wù)器可以通過該頭部告知瀏覽器將要傳送文件的大小(bytes),。
對(duì)于文件下載來說這個(gè)信息相當(dāng)?shù)挠杏?。這就是為什么瀏覽器知道下載進(jìn)度的原因。 例如,,這里我寫了一段虛擬腳本,,來模擬一個(gè)慢速下載。
結(jié)果將會(huì)是這樣的: 現(xiàn)在,,我將Content-Length頭部注釋掉:
結(jié)果就變成了這樣: 這個(gè)瀏覽器只會(huì)告訴你已下載了多少,,但不會(huì)告訴你總共需要下載多少。而且進(jìn)度條也不會(huì)顯示進(jìn)度。 Etag這是另一個(gè)為緩存而產(chǎn)生的頭部信息,。它看起來會(huì)是這樣:
服務(wù)器可能會(huì)將該信息和每個(gè)被發(fā)送文件一起響應(yīng)給瀏覽器,。該值可以包含文檔的最后修改日期,文件大小或者文件校驗(yàn)和,。瀏覽 會(huì)把它和所接收到的文檔一起緩存,。下一次當(dāng)瀏覽器再次請(qǐng)求同一文件時(shí)將會(huì)發(fā)送如下的HTTP請(qǐng)求:
如果所請(qǐng)求的文檔Etag值和它一致,服務(wù)器將會(huì)發(fā)送304狀態(tài)碼,,而不是2oo,。并且不返回內(nèi)容。瀏覽器此時(shí)就會(huì)從緩存加載該文件,。 Last-Modified顧名思義,,這個(gè)頭部信息用GMT格式表明了文檔的最后修改時(shí)間:
它提供了另一種緩存機(jī)制。瀏覽器可能會(huì)發(fā)送這樣的請(qǐng)求:
在If-Modified-Since一節(jié)我們已經(jīng)討論過了,。 Location這個(gè)頭部是用來重定向的,。如果響應(yīng)代碼為 301 或者 302 ,服務(wù)器就必須發(fā)送該頭部,。例如,,當(dāng)你訪問 http://www. 時(shí)瀏覽器就會(huì)收到如下的響應(yīng):
在PHP中你可以通過這種方式對(duì)訪客重定向: 默認(rèn)會(huì)發(fā)送302狀態(tài)碼,如果你想發(fā)送301,,就這樣寫:
Set-Cookie當(dāng)一個(gè)網(wǎng)站需要設(shè)置或者更新你瀏覽的cookie信息時(shí),,它就會(huì)使用這樣的頭部:
每個(gè)cookie會(huì)作為單獨(dú)的一條頭部信息。注意,,通過js設(shè)置cookie將不會(huì)體現(xiàn)在HTTP頭中,。 在PHP中,你可以通過setcookie()函 數(shù)來設(shè)置cookie,,PHP會(huì)發(fā)送合適的HTTP 頭,。
它會(huì)發(fā)送這樣的頭信息:
如果未指定到期時(shí)間,cookie就會(huì)在瀏覽器關(guān)閉后被刪除,。 WWW-Authenticate一個(gè)網(wǎng)站可能會(huì)通過HTTP發(fā)送這個(gè)頭部信息來驗(yàn)證用戶,。當(dāng)瀏覽器看到頭部有這個(gè)響應(yīng)時(shí)就會(huì)打開一個(gè)彈出窗。
它會(huì)看起來像這樣: 在PHP手冊(cè)的一章中就有一段簡(jiǎn)單的代碼演示了如果用PHP做這樣的事情:
Content-Encoding這個(gè)頭部通常會(huì)在返回內(nèi)容被壓縮時(shí)設(shè)置,。
在PHP中,如果你調(diào)用了ob_gzhandler()函 數(shù),,這個(gè)頭部將會(huì)自動(dòng)被設(shè)置,。 |
|