HTTP請求中瀏覽器的緩存機制
流程
當資源第一次被訪問的時候,HTTP頭部如下
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返回頭部如下
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的狀態碼,并在頭部攜帶上當前資源的一些描述信息,如
Etag // 指示資源的狀態唯一標識
Expires // 指示資源在瀏覽器緩存中的過期時間
接著瀏覽器會將文件緩存到Cache目錄下,并同時保存文件的上述信息
當第二次請求該文件時,瀏覽器會先檢查Cache目錄下是否含有該文件,如果有,并且還沒到Expires設置的時間,即文件還沒有過期,那么此時瀏覽器將直接從Cache目錄中讀取文件,而不再發送請求
如果文件此時已經過期,則瀏覽器會發送一次HTTP請求到WebServer,并在頭部攜帶上當前文件的如下信息
If-None-Match "8fb8b-14-4794674acdcc0"
即把上一次修改的時間,以及上一次請求返回的Etag值一起發送給服務器。服務器在接收到這個請求的時候,先解析Header里頭的信息,然后校驗該頭部信息。
如果該文件從上次時間到現在都沒有過修改或者Etag信息沒有變化,則服務端將直接返回一個304的狀態,而不再返回文件資源,狀態頭部如下
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并不會修改另一個消息處理過程中的緩存處理過程。請求時的緩存指令包括
響應消息中的指令包括
各個消息中的指令含義如下:
-
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-None-Match "2360492659"
Pragma: no-cache // 禁止緩存
FF:
If-None-Match "2360492659"
Cache-Control max-age=0 // 文件立即過期
強制刷新(Ctrl+F5)
效果和無緩存時候一致,返回200的結果
一些特殊的資源
IFRAME
FLASH
異步獲取的數據
待研究……