HTTP請求
HTTP請求的格式如下所示:
<request-line>
<headers>
<blank line>
[<request-body>]
在HTTP請求中,第一行必須是一個請求行(request line),用來說明請求類型、要訪問的資源以及使用的HTTP版本。緊接着是一個首部(header)小節,用來說明服務器要使用的附加信息。在首部之后是一個空行,再此之后可以添加任意的其他數據[稱之為主體(body)]。
在HTTP中,定義了多種請求類型,通常我們關心的只有GET請求和POST請求。只要在Web瀏覽器上輸入一個URL,瀏覽器就將基於該URL向服務器發送一個GET請求,以告訴服務器獲取並返回什么資源。對於www.baidu.com的GET請求如下所示:
GET / HTTP/1.1 Host: www.baidu.com User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050225 Firefox/1.0.1 Connection: Keep-Alive
請求行的第一部分說明了該請求是GET請求。該行的第二部分是一個斜杠(/),用來說明請求的是該域名的根目錄。該行的最后一部分說明使用的是HTTP 1.1版本(另一個可選項是1.0)。那么請求發到哪里去呢?這就是第二行的內容。
第2行是請求的第一個首部,HOST。首部HOST將指出請求的目的地。結合HOST和上一行中的斜杠(/),可以通知服務器請求的是www.baidu.com/(HTTP 1.1才需要使用首部HOST,而原來的1.0版本則不需要使用)。第三行中包含的是首部User-Agent,服務器端和客戶端腳本都能夠訪問它,它是瀏覽器類型檢測邏輯的重要基礎。該信息由你使用的瀏覽器來定義(在本例中是Firefox 1.0.1),並且在每個請求中將自動發送。最后一行是首部Connection,通常將瀏覽器操作設置為Keep-Alive(當然也可以設置為其他值)。注意,在最后一個首部之后有一個空行。即使不存在請求主體,這個空行也是必需的。
要發送GET請求的參數,則必須將這些額外的信息附在URL本身的后面。其格式類似於:
URL ? name1=value1&name2=value2&..&nameN=valueN
該信息稱之為查詢字符串(query string),它將會復制在HTTP請求的請求行中,如下所示:
GET /books/?name=Professional%20Ajax HTTP/1.1 Host: www.baidu.com User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050225 Firefox/1.0.1 Connection: Keep-Alive
注意,為了將文本“Professional Ajax”作為URL的參數,需要編碼處理其內容,將空格替換成%20,這稱為URL編碼(URL encoding),常用於HTTP的許多地方(JavaScript提供了內建的函數來處理URL編碼和解碼)。“名稱—值”(name—value)對用 & 隔開。絕大部分的服務器端技術能夠自動對請求主體進行解碼,並為這些值的訪問提供一些邏輯方式。當然,如何使用這些數據還是由服務器決定的。
另一方面,POST請求在請求主體中為服務器提供了一些附加的信息。通常,當填寫一個在線表單並提交它時,這些填入的數據將以POST請求的方式發送給服務器。
以下就是一個典型的POST請求:
POST / HTTP/1.1 Host: www.baidu.com User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050225 Firefox/1.0.1 Content-Type: application/x-www-form-urlencoded Content-Length: 40 Connection: Keep-Alive name=Professional%20Ajax&publisher=Wiley
從上面可以發現, POST請求和GET請求之間有一些區別。首先,請求行開始處的GET改為了POST,以表示不同的請求類型。你會發現首部Host和User-Agent仍然存在,在后面有兩個新行。其中首部Content-Type說明了請求主體的內容是如何編碼的。瀏覽器始終以application/ x-www-form- urlencoded的格式編碼來傳送數據,這是針對簡單URL編碼的MIME類型。首部Content-Length說明了請求主體的字節數。在首部Connection后是一個空行,再后面就是請求主體。與大多數瀏覽器的POST請求一樣,這是以簡單的“名稱—值”對的形式給出的,其中name是Professional Ajax,publisher是Wiley。你可以以同樣的格式來組織URL的查詢字符串參數。
下面是一些最常見的請求頭:
Accept:瀏覽器可接受的MIME類型。
Accept - Charset:瀏覽器可接受的字符集。
Accept - Encoding:瀏覽器能夠進行解碼的數據編碼方式,比如gzip。Servlet能夠向支持gzip的瀏覽器返回經gzip編碼的HTML頁面。許多情形下這可以減少5到10倍的下載時間。
Accept - Language:瀏覽器所希望的語言種類,當服務器能夠提供一種以上的語言版本時要用到。
Authorization:授權信息,通常出現在對服務器發送的WWW - Authenticate頭的應答中。
Connection:表示是否需要持久連接。如果Servlet看到這里的值為“Keep - Alive”,或者看到請求使用的是HTTP 1.1(HTTP 1.1默認進行持久連接),它就可以利用持久連接的優點,當頁面包含多個元素時(例如Applet,圖片),顯著地減少下載所需要的時間。要實現這一點,Servlet需要在應答中發送一個Content - Length頭,最簡單的實現方法是:先把內容寫入ByteArrayOutputStream,然后在正式寫出內容之前計算它的大小。
Content - Length:表示請求消息正文的長度。
Cookie:這是最重要的請求頭信息之一,參見后面《Cookie處理》一章中的討論。
From:請求發送者的email地址,由一些特殊的Web客戶程序使用,瀏覽器不會用到它。
Host:初始URL中的主機和端口。
If - Modified - Since:只有當所請求的內容在指定的日期之后又經過修改才返回它,否則返回304“Not Modified”應答。
Pragma:指定“no - cache”值表示服務器必須返回一個刷新后的文檔,即使它是代理服務器而且已經有了頁面的本地拷貝。
Referer:包含一個URL,用戶從該URL代表的頁面出發訪問當前請求的頁面。
User - Agent:瀏覽器類型,如果Servlet返回的內容與瀏覽器類型有關則該值非常有用。
UA - Pixels,UA - Color,UA - OS,UA - CPU:由某些版本的IE瀏覽器所發送的非標准的請求頭,表示屏幕大小、顏色深度、操作系統和CPU類型。
HTTP響應
如下所示,HTTP響應的格式與請求的格式十分類似:
<status-line>
<headers>
<blank line>
[<response-body>]
正如你所見,在響應中唯一真正的區別在於第一行中用狀態信息代替了請求信息。狀態行(status line)通過提供一個狀態碼來說明所請求的資源情況。以下就是一個HTTP響應的例子:
HTTP/1.1 200 OK Date: Sat, 31 Dec 2005 23:59:59 GMT Content-Type: text/html;charset=ISO-8859-1 Content-Length: 122 <html> <head> <title>Wrox Homepage</title> </head> <body> <!-- body goes here --> </body> </html>
在本例中,狀態行給出的HTTP狀態代碼是200,以及消息OK。狀態行始終包含的是狀態碼和相應的簡短消息,以避免混亂。最常用的狀態碼有:
◆200 (OK): 找到了該資源,並且一切正常。 ◆304 (NOT MODIFIED): 該資源在上次請求之后沒有任何修改。這通常用於瀏覽器的緩存機制。 ◆401 (UNAUTHORIZED): 客戶端無權訪問該資源。這通常會使得瀏覽器要求用戶輸入用戶名和密碼,以登錄到服務器。 ◆403 (FORBIDDEN): 客戶端未能獲得授權。這通常是在401之后輸入了不正確的用戶名或密碼。 ◆404 (NOT FOUND): 在指定的位置不存在所申請的資源。
在狀態行之后是一些首部。通常,服務器會返回一個名為Data的首部,用來說明響應生成的日期和時間(服務器通常還會返回一些關於其自身的信息,盡管並非是必需的)。接下來的兩個首部大家應該熟悉,就是與POST請求中一樣的Content-Type和Content-Length。在本例中,首部Content-Type指定了MIME類型HTML(text/html),其編碼類型是ISO-8859-1(這是針對美國英語資源的編碼標准)。響應主體所包含的就是所請求資源的HTML源文件(盡管還可能包含純文本或其他資源類型的二進制數據)。瀏覽器將把這些數據顯示給用戶。
注意,這里並沒有指明針對該響應的請求類型,不過這對於服務器並不重要。客戶端知道每種類型的請求將返回什么類型的數據,並決定如何使用這些數據。
GET
通過請求URI得到資源
POST,
用於添加新的內容
PUT
用於修改某個內容
DELETE,
刪除某個內容
CONNECT,
用於代理進行傳輸,如使用SSL
OPTIONS
詢問可以執行哪些方法
PATCH,
部分文檔更改
PROPFIND, (wedav)
查看屬性
PROPPATCH, (wedav)
設置屬性
MKCOL, (wedav)
創建集合(文件夾)
COPY, (wedav)
拷貝
MOVE, (wedav)
移動
LOCK, (wedav)
加鎖
UNLOCK (wedav)
解鎖
TRACE
用於遠程診斷服務器
HEAD
類似於GET, 但是不返回body信息,用於檢查對象是否存在,以及得到對象的元數據
二:HTTP請求中的瀏覽器緩存機制
流程
當資源第一次被訪問的時候,HTTP頭部如下
(Request-Line) GET /a.html HTTP/1.1
Host 127.0.0.1
User-Agent Mozilla/5.0 (X11; U; Linux i686; zh-CN; rv:1.9.0.15) Gecko/2009102815 Ubuntu/9.04 (jaunty) Firefox/3.0.15
Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language zh-cn,zh;q=0.5
Accept-Encoding gzip,deflate
Accept-Charset gb2312,utf-8;q=0.7,;q=0.7
Keep-Alive 300
Connection keep-alive
HTTP返回頭部如下
(Status-Line) HTTP/1.1 200 OK
Date Thu, 26 Nov 2009 13:50:54 GMT
Server Apache/2.2.11 (Unix) PHP/5.2.9
Last-Modified Thu, 26 Nov 2009 13:50:19 GMT
Etag "8fb8b-14-4794674acdcc0"
Accept-Ranges bytes
Content-Length 20
Keep-Alive timeout=5, max=100
Connection Keep-Alive
Content-Type text/html
當資源第一次被訪問的時候,http返回200的狀態碼,並在頭部攜帶上當前資源的一些描述信息,如
Last-Modified // 指示最后修改的時間
Etag // 指示資源的狀態唯一標識
Expires // 指示資源在瀏覽器緩存中的過期時間
接着瀏覽器會將文件緩存到Cache目錄下,並同時保存文件的上述信息
當第二次請求該文件時,瀏覽器會先檢查Cache目錄下是否含有該文件,如果有,並且還沒到Expires設置的時間,即文件還沒有過期,那么此時瀏覽器將直接從Cache目錄中讀取文件,而不再發送請求
如果文件此時已經過期,則瀏覽器會發送一次HTTP請求到WebServer,並在頭部攜帶上當前文件的如下信息
If-Modified-Since Thu, 26 Nov 2009 13:50:19 GMT
If-None-Match "8fb8b-14-4794674acdcc0"
即把上一次修改的時間,以及上一次請求返回的Etag值一起發送給服務器。服務器在接收到這個請求的時候,先解析Header里頭的信息,然后校驗該頭部信息。
如果該文件從上次時間到現在都沒有過修改或者Etag信息沒有變化,則服務端將直接返回一個304的狀態,而不再返回文件資源,狀態頭部如下
(Status-Line) HTTP/1.1 304 Not Modified
Date Thu, 26 Nov 2009 14:09:07 GMT
Server Apache/2.2.11 (Unix) PHP/5.2.9
Connection Keep-Alive
Keep-Alive timeout=5, max=100
Etag "8fb8b-14-4794674acdcc0"
這樣,就能夠很大程度上減少網絡帶寬以及提升用戶的瀏覽器體驗。
當然,如果服務器經過匹配發現文件修改過了,就會將文件資源返回,並帶上新文件狀態信息。
基本字段
Pragma
Pragma頭域用來包含實現特定的指令,最常用的是Pragma:no-cache。在HTTP/1.1協議中,它的含義和Cache- Control:no-cache相同。
Expires
文件在本地緩存的過期時間,如果瀏覽器發現緩存中的文件沒有過期,則不發送請求(有例外,后面介紹)
Cache-Control
Cache -Control指定請求和響應遵循的緩存機制。
在請求消息或響應消息中設置 Cache-Control並不會修改另一個消息處理過程中的緩存處理過程。請求時的緩存指令包括
no-cache、no-store、max-age、 max-stale、min-fresh、only-if-cached
響應消息中的指令包括
public、private、no-cache、no- store、no-transform、must-revalidate、proxy-revalidate、max-age
各個消息中的指令含義如下:
-
Public指示響應可被任何緩存區緩存。
-
Private指示對於單個用戶的整個或部分響應消息,不能被共享緩存處理。這允許服務器僅僅描述當用戶的部分響應消息,此響應消息對於其他用戶的請求無效。
-
no-cache指示請求或響應消息不能緩存
-
no-store用於防止重要的信息被無意的發布。在請求消息中發送將使得請求和響應消息都不使用緩存。
-
max-age指示客戶機可以接收生存期不大於指定時間(以秒為單位)的響應。
-
min-fresh指示客戶機可以接收響應時間小於當前時間加上指定時間的響應。
-
max-stale指示客戶機可以接收超出超時期間的響應消息。如果指定max-stale消息的值,那么客戶機可以接收超出超時期指定值之內的響應消息。
Etag/If-None-Match
一對驗證文件實體的標記“Entity Tag”的響應/請求頭Apache中,ETag的值,默認是對文件的索引節(INode),大小(Size)和最后修改時間(MTime)進行Hash后得到的
Last-Modified/If-Modified-Since
一對驗證文件的修改時間的響應/請求頭
Expires、Cache-Control、Last-Modified、ETag是RFC 2616(HTTP/1.1)協議中和網頁緩存相關的幾個字段。
前兩個用來控制緩存的失效日期,瀏覽器可通過它來判定,需不需要發出HTTP請求;
后兩個用來驗證網頁的有效性,服務器端利用它來驗證這個文件是否需要重新返回
Last-Modified VS Etag
既然有了Last-Modified,為什么還要用ETag字段呢?因為如果在一秒鍾之內對一個文件進行兩次更改,Last-Modified就會不正確。因此,HTTP/1.1利用Entity Tag頭提供了更加嚴格的驗證。
不同的情況
上面描述的是一個普通的瀏覽器緩存狀態,在實際應用中,如頁面跳轉(點擊頁面鏈接跳轉,window.open,在地址欄敲回車,刷新頁面)等操作,會有一些區別
普通頁面跳轉
普通頁面跳轉包括鏈接點擊跳轉,用js腳本打開新頁面(window.open)
無緩存情況下,請求會返回所有資源結果
設置Expires並且未過期時,瀏覽器將不會發出http請求
如果Expires過期,則會發送相應請求,並附帶上Last-Modifed等信息,供服務器校驗
頁面刷新(F5)
這種情況一下,一般會看到很多304的請求,就是說即便資源設置了Expires且未過期,瀏覽器也會發送相應請求
IE和FF稍有區別
IE:
If-Modified-Since Wed, 18 Nov 2009 15:54:52 GMT
If-None-Match "2360492659"
Pragma: no-cache // 禁止緩存
FF:
If-Modified-Since Wed, 18 Nov 2009 15:54:52 GMT
If-None-Match "2360492659"
Cache-Control max-age=0 // 文件立即過期
強制刷新(Ctrl+F5)
效果和無緩存時候一致,返回200的結果
一些特殊的資源
IFRAME
FLASH
異步獲取的數據
待研究……
主要參考:http://www.cnblogs.com/yin-jingyu/archive/2011/08/01/2123548.html
