瀏覽器緩存
瀏覽器緩存的知識是前端工程師必須要掌握的,因為這些知識直接影響到你的頁面的用戶體驗,影響到你的頁面的加載策略。接下來將要詳細的講述瀏覽器緩存的概 念和原理,新人要仔細閱讀,甚至要多次反芻,緩存的知識除了和瀏覽器有關,還涉及到HTTP協議,所以這也是比較難於掌握的內容。
一般在硬件中,緩存在硬件中分一級緩存,二級緩存。但在軟件中的緩存卻不一樣。
狹義上講緩存就叫高速緩存,嚴格講就是將數據暫時存放到某個地方。先要聲明下,我的定義可能不嚴格,但這是我的理解,通俗易懂。
至於存到什么地方就有很多方式,可放到文件,內存中(如session),還有cache(高速緩存),還有 cookie,session,viewstate,這些是我們經常用到的,但可以認為他們是緩存數據。其實cache跟session有相似功能,但 cache可在代碼中設置過期時間,依賴項。所謂依賴項(例如:微軟的類cachedependcy sqlCacheDependency)當依賴項變動了,系統會通知cache過期,無效。以上只是說緩存,緩存可是有服務器緩存,客戶端緩存啊。
近些天研究了下客戶端緩存(即瀏覽器緩存),我想跟大家分享,有什么不同意見可評論。
估計大多數人很少說客戶端緩存,包括我在內。那是因為我們編程時基本不考慮客戶端緩存,書上也寫得少。其實瀏覽器自動會管理緩存,但了解它至少知道有這么回事,有事編程還要控制客戶端緩存。
瀏覽器緩存就是當你打開一個網頁,瀏覽器會自動下載副本到你電腦上,就相當於你另存為網頁到某個地方而已,只不過這里是自動而已。當然不是瀏覽器能把各種 網頁都能下載到本地電腦上,它是有特殊情況。一般html,后者request是get請求,而post一般不緩存。(這個后面會說到)
當然客戶端緩存是否需要是可以在服務端代碼上控制的。那就是響應頭。
響應頭告訴緩存器不要保留緩存,緩存器就不會緩存相應內容;
如果請求信息是需要認證或者安全加密的,相應內容也不會被緩存;
校驗參數非常重要,如果回應中1個參數都不存在,並且沒有任何信息說明保鮮期(Expires或Cache-Control)的情況下,緩存將不會存儲任何副本; 最常見的校驗參數是文檔的最后修改時間,通過最后Last-Modified頭信息可以,當一份緩存包含Last-Modified信息,他基於此信息,通過添加一個If-Modified-Since請求參數,向服務器查詢:這個副本從上次查看后是否被修改了。 HTTP 1.1介紹了另外一個校驗參數: ETag,服務器是服務器生成的唯一標識符ETag,每次副本的標簽都會變化。由於服務器控制了ETag如何生成,緩存服務器可以通過If-None-Match請求的返回沒變則當前副本和原件完全一致。 所有的緩存服務器都使用Last-Modified時間來確定副本是否夠新,而ETag校驗正變得越來越流行。
響應頭如果是POST模式遞交數據,則返回的頁面大部分不會被瀏覽器緩存,如果你發送內容通過URL和查詢(通過GET模式),則返回的內容可以緩存下來供以后使用。
HTTP協議中關於緩存的信息頭關鍵字包括Cache-Control(HTTP1.1),Pragma(HTTP1.0),last-Modified,Expires等。
http://hovertree.com/menu/webfront/
緩存控制頭 Cache-Control
Cache-Control 是最重要的規則。這個字段用於指定所有緩存機制在整個請求/響應鏈中必須服從的指令。這些指令指定用於阻止緩存對請求或響應造成不利干擾的行為。這些指令 通常覆蓋默認緩存算法。緩存指令是單向的,即請求中存在一個指令並不意味着響應中將存在同一個指令。
cache-control 定義是:Cache-Control = “Cache-Control” “:” cache-directive。表 1 展示了適用的值。
表 1. 常用 cache-directive 值
Cache-directive | 說明 |
---|---|
public | 所有內容都將被緩存 |
private | 內容只緩存到私有緩存中 |
no-cache | 所有內容都不會被緩存 |
no-store | 所有內容都不會被緩存到緩存或 Internet 臨時文件中 |
must-revalidation/proxy-revalidation | 如果緩存的內容失效,請求必須發送到服務器/代理以進行重新驗證 |
max-age=xxx (xxx is numeric) | 緩存的內容將在 xxx 秒后失效, 這個選項只在HTTP 1.1可用, 並如果和Last-Modified一起使用時, 優先級較高 |
表 2 表明在不同的情形下,瀏覽器是將請求重新發送到服務器還是使用緩存的內容。
表 2. 對 cache-directive 值的瀏覽器響應
Cache-directive | 打開一個新的瀏覽器窗口 | 在原窗口中單擊 Enter 按鈕 | 刷新 | 單擊 Back 按鈕 |
---|---|---|---|---|
public | 瀏覽器呈現來自緩存的頁面 | 瀏覽器呈現來自緩存的頁面 | 瀏覽器重新發送請求到服務器 | 瀏覽器呈現來自緩存的頁面 |
private | 瀏覽器重新發送請求到服務器 | 第一次,瀏覽器重新發送請求到服務器;此后,瀏覽器呈現來自緩存的頁面 | 瀏覽器重新發送請求到服務器 | 瀏覽器呈現來自緩存的頁面 |
no-cache/no-store | 瀏覽器重新發送請求到服務器 | 瀏覽器重新發送請求到服務器 | 瀏覽器重新發送請求到服務器 | 瀏覽器重新發送請求到服務器 |
must-revalidation/proxy-revalidation | 瀏覽器重新發送請求到服務器 | 第一次,瀏覽器重新發送請求到服務器;此后,瀏覽器呈現來自緩存的頁面 | 瀏覽器重新發送請求到服務器 | 瀏覽器呈現來自緩存的頁面 |
max-age=xxx (xxx is numeric) | 在 xxx 秒后,瀏覽器重新發送請求到服務器 | 在 xxx 秒后,瀏覽器重新發送請求到服務器 | 瀏覽器重新發送請求到服務器 | 在 xxx 秒后,瀏覽器重新發送請求到服務器 |
Cache-Control是關於瀏覽器緩存的最重要的設置,因為它覆蓋其他設置,比如 Expires 和 Last-Modified。另外,由於瀏覽器的行為基本相同,這個屬性是處理跨瀏覽器緩存問題的最有效的方法。
過期頭 (Expires)
Expires 頭部字段提供一個日期和時間,響應在該日期和時間后被認為失效。失效的緩存條目通常不會被緩存(無論是代理緩存還是用戶代理緩存)返回,除非首先通過原始 服務器(或者擁有該實體的最新副本的中介緩存)驗證。(注意:cache-control max-age 和 s-maxage 將覆蓋 Expires 頭部。)
Expires 字段接收以下格式的值:“Expires: Sun, 08 Nov 2009 03:37:26 GMT”。如果查看內容時的日期在給定的日期之前,則認為該內容沒有失效並從緩存中提取出來。反之,則認為該內容失效,緩存將采取一些措施。表 3-6 表明針對不同用戶操作的不同瀏覽器的行為。
表 3. 當用戶打開一個新的瀏覽器窗口時的失效操作
Firefox 3.5 | IE 8 | Chrome 3 | Safari 4 | |
---|---|---|---|---|
內容沒有失效 | 瀏覽器呈現來自緩存的頁面 | 瀏覽器重新發送請求到服務器。返回代碼是 200 | 瀏覽器呈現來自緩存的頁面 | 瀏覽器呈現來自緩存的頁面 |
內容失效 | 瀏覽器重新發送請求到服務器。返回代碼是 200 | 瀏覽器重新發送請求到服務器。返回代碼是 200 | 瀏覽器重新發送請求到服務器。返回代碼是 200 | 瀏覽器重新發送請求到服務器。返回代碼是 200 |
表 4. 當用戶在原始瀏覽器窗口中單擊 Enter 按鈕時的失效操作
Firefox 3.5 | IE 8 | Chrome 3 | Safari 4 | |
---|---|---|---|---|
內容沒有失效 | 瀏覽器呈現來自緩存的頁面 | 瀏覽器呈現來自緩存的頁面 | 瀏覽器重新發送請求到服務器。返回代碼是 304 | 瀏覽器重新發送請求到服務器。返回代碼是 304 |
內容失效 | 瀏覽器重新發送請求到服務器。返回代碼是 200 | 瀏覽器呈現來自緩存的頁面 | 瀏覽器重新發送請求到服務器。返回代碼是 200 | 瀏覽器重新發送請求到服務器。返回代碼是 200 |
表 5. 當用戶按 F5 鍵刷新頁面時的失效操作
Firefox 3.5 | IE 8 | Chrome 3 | Safari 4 | |
---|---|---|---|---|
內容沒有失效 | 瀏覽器重新發送請求到服務器。返回代碼是 304 | 瀏覽器重新發送請求到服務器。返回代碼是 304 | 瀏覽器重新發送請求到服務器。返回代碼是 304 | 瀏覽器重新發送請求到服務器。返回代碼是 304 |
內容失效 | 瀏覽器重新發送請求到服務器。返回代碼是 200 | 瀏覽器重新發送請求到服務器。返回代碼是 200 | 瀏覽器重新發送請求到服務器。返回代碼是 200 | 瀏覽器重新發送請求到服務器。返回代碼是 200 |
表 6. 當用戶單擊 Back 或 Forward 按鈕時的失效操作
Firefox 3.5 | IE 8 | Chrome 3 | Safari 4 | |
---|---|---|---|---|
內容沒有失效 | 瀏覽器呈現來自緩存的頁面 | 瀏覽器呈現來自緩存的頁面 | 瀏覽器呈現來自緩存的頁面 | 瀏覽器呈現來自緩存的頁面 |
內容失效 | 瀏覽器呈現來自緩存的頁面 | 瀏覽器呈現來自緩存的頁面 | 瀏覽器呈現來自緩存的頁面 | 瀏覽器重新發送請求到服務器。返回代碼是 200 |
注意:所有瀏覽器都假定為使用默認設置運行。
控制文件是否有修改 Last-Modified/E-Tag
Last-Modified 實體頭部字段值通常用作一個緩存驗證器。簡單來說,如果實體值在 Last-Modified 值之后沒有被更改,則認為該緩存條目有效。ETag 響應頭部字段值是一個實體標記,它提供一個 “不透明” 的緩存驗證器。這可能在以下幾種情況下提供更可靠的驗證:不方便存儲修改日期;HTTP 日期值的 one-second 解決方案不夠用;或者原始服務器希望避免由於使用修改日期而導致的某些沖突。
不同的瀏覽器有不同的配置行為。表 7-10 表明針對不同用戶操作的不同瀏覽器的行為。
表 7. 當用戶打開一個新的瀏覽器窗口時的 Last-Modified E-Tag 操作
Firefox 3.5 | IE 8 | Chrome 3 | Safari 4 | |
---|---|---|---|---|
內容自上次訪問以來沒有被修改 | 瀏覽器重新發送請求到服務器。返回代碼是 304 | 瀏覽器重新發送請求到服務器。返回代碼是 200 | 瀏覽器重新發送請求到服務器。返回代碼是 304 | 瀏覽器重新發送請求到服務器。返回代碼是 304 |
內容自上次訪問以來已經被修改 | 瀏覽器重新發送請求到服務器。返回代碼是 200 | 瀏覽器重新發送請求到服務器。返回代碼是 200 | 瀏覽器重新發送請求到服務器。返回代碼是 200 | 瀏覽器重新發送請求到服務器。返回代碼是 200 |
表 8. 當用戶在原始瀏覽器窗口中單擊 Enter 按鈕時的 Last-Modified E-Tag 操作
Firefox 3.5 | IE 8 | Chrome 3 | Safari 4 | |
---|---|---|---|---|
內容自上次訪問以來沒有被修改 | 瀏覽器呈現來自緩存的頁面 | 瀏覽器呈現來自緩存的頁面 | 瀏覽器重新發送請求到服務器。返回代碼是 304 | 瀏覽器重新發送請求到服務器。返回代碼是 304 |
內容自上次訪問以來已經被修改 | 瀏覽器重新發送請求到服務器。返回代碼是 200 | 瀏覽器呈現來自緩存的頁面 | 瀏覽器重新發送請求到服務器。返回代碼是 200 | 瀏覽器重新發送請求到服務器。返回代碼是 200 |
表 9. 當用戶按 F5 鍵刷新頁面時的 Last-Modified E-Tag 操作
Firefox 3.5 | IE 8 | Chrome 3 | Safari 4 | |
---|---|---|---|---|
內容自上次訪問以來沒有被修改 | 瀏覽器重新發送請求到服務器。返回代碼是 304 | 瀏覽器重新發送請求到服務器。返回代碼是 304 | 瀏覽器重新發送請求到服務器。返回代碼是 304 | 瀏覽器重新發送請求到服務器。返回代碼是 304 |
內容自上次訪問以來已經被修改 | 瀏覽器重新發送請求到服務器。返回代碼是 200 | 瀏覽器重新發送請求到服務器。返回代碼是 200 | 瀏覽器重新發送請求到服務器。返回代碼是 200 | 瀏覽器重新發送請求到服務器。返回代碼是 200 |
表 10. 沒有緩存設置且用戶單擊 Back 或 Forward 按鈕
Firefox 3.5 | IE 8 | Chrome 3 | Safari 4 | |
---|---|---|---|---|
內容自上次訪問以來沒有被修改 | 瀏覽器呈現來自緩存的頁面 | 瀏覽器呈現來自緩存的頁面 | 瀏覽器呈現來自緩存的頁面 | 瀏覽器呈現來自緩存的頁面 |
內容自上次訪問以來已經被修改 | 瀏覽器呈現來自緩存的頁面 | 瀏覽器呈現來自緩存的頁面 | 瀏覽器呈現來自緩存的頁面 | 瀏覽器重新發送請求到服務器。返回代碼是 200 |
注意:所有瀏覽器都假定使用默認設置運行。
不進行任何緩存相關設置
如果您不定義任何緩存相關設置,則不同的瀏覽器有不同的行為。有時,同一個瀏覽器在相同的情形下每次運行時的行為都是不同的。情況可能很復雜。另外,有些不該緩存的內容如果被緩存,將會導致安全問題。 不同的瀏覽器有不同的行為。表 11 展示了不同的瀏覽器行為。
表 11. 沒有緩存設置且用戶打開一個新的瀏覽器窗口
Firefox 3.5 | IE 8 | Chrome 3 | Safari 4 | |
---|---|---|---|---|
打開一個新頁面 | 瀏覽器重新發送請求到服務器。返回代碼是 200 | 瀏覽器重新發送請求到服務器。返回代碼是 200 | 瀏覽器重新發送請求到服務器。返回代碼是 200 | 瀏覽器重新發送請求到服務器。返回代碼是 200 |
在原始窗口中單擊 Enter 按鈕 | 瀏覽器重新發送請求到服務器。返回代碼是 200 | 瀏覽器呈現來自緩存的頁面。 | 瀏覽器重新發送請求到服務器。返回代碼是 200 | 瀏覽器重新發送請求到服務器。返回代碼是 200 |
按 F5 鍵刷新 | 瀏覽器重新發送請求到服務器。返回代碼是 200 | 瀏覽器重新發送請求到服務器。返回代碼是 200 | 瀏覽器重新發送請求到服務器。返回代碼是 200 | 瀏覽器重新發送請求到服務器。返回代碼是 200 |
單擊 Back 或 Forward 按鈕 | 瀏覽器呈現來自緩存的頁面。 | 瀏覽器呈現來自緩存的頁面。 | 瀏覽器重新發送請求到服務器。返回代碼是 200 | 瀏覽器重新發送請求到服務器。返回代碼是 200 |
注意:所有瀏覽器都假定使用默認設置運行。
關鍵結論
最后, 概括下關鍵的結論
操作 | 行為 |
---|---|
打開新窗口 | 如果指定cache- control的值為private、no-cache、must-revalidate,那么打開新窗口訪問時都會重新訪問服務器。而如果指定了 max-age值,那么在此值內的時間里就不會重新訪問服務器,例如:Cache-control: max-age=5 表示當訪問此網頁后的5秒內再次訪問不會去服務器. |
在地址欄回車 | 如果值為private或must-revalidate,則只有第一次訪問時會訪問服務器,以后就不再訪問。如果值為no-cache,那么每次都會訪問。如果值為max-age,則在過期之前不會重復訪問。 |
按后退按扭 | 如果值為private、must-revalidate、max-age,則不會重訪問,而如果為no-cache,則每次都重復訪問. |
按刷新按扭 | 無論為 |