瀏覽器緩存和304小結

關於瀏覽器緩存

瀏覽器的資源請求,若是使用了緩存基本上是兩種狀況css

  • status code: 200 ok ( from cache )
  • status code: 304 Not Modified

browser-cache

browser-cache

上面兩種方式有什麼區別呢?簡單地說,第一種方式是不向瀏覽器發送請求,直接使用本地緩存文件。第二種方式,瀏覽器雖然發現了本地有該資源的緩存,可是不肯定是不是最新的,因而想服務器詢問,若服務器認爲瀏覽器的緩存版本還可用,那麼便會返回304。html

瀏覽器關於緩存使用的決策

那麼,瀏覽器如何決定是使用哪一種方式呢?這就和服務器在請求返回中的Header字段有關了。下面對相關的字段進行簡單介紹。node

Cache-Control

Cache-Control 是最重要的規則。這個字段用於指定全部緩存機制在整個請求/響應鏈中必須服從的指令。該字段一般覆蓋默認緩存算法。另外,緩存指令是單向的,即請求中存在一個指令並不意味着響應中將存在同一個指令。git

簡單地說,該字段用於控制瀏覽器在什麼狀況下直接使用本地緩存而不向服務器發送請求。通常具備如下值:github

  • public: 全部內容都將被緩存
  • private: 內容只緩存到似有緩存中
  • no-cache: 全部內容都不會被緩存
  • no-store: 全部內容都不會被緩存到緩存或者internet臨時文件中
  • must-revalidation/proxy-revalidation: 若是緩存的內容失效,請求必須發送到服務器/代理以進行從新驗證
  • max-age=xxx( xxx is numeric ): 緩存的內容將在 xxx 秒後失效, 這個選項只在HTTP 1.1可用, 並若是和Last-Modified一塊兒使用時, 優先級較高

其中最經常使用的屬性即是 max-age, 這個字段很簡單,就是瀏覽器在資源成功請求後的制定時間內,都將直接調用本地緩存和不會向服務器去請求數據。算法

Expires

Expires 頭部字段提供一個日期和時間,在該日期前的全部對該資源的請求都會直接使用瀏覽器緩存而不用向服務器請求(注意:cache-control max-age 和 s-maxage 將覆蓋 Expires 頭部。)apache

Expires 字段接收如下格式的值:「Expires: Sun, 08 Nov 2009 03:37:26 GMT」。瀏覽器

可是使用Expires存在服務器端時間和瀏覽器時間不一致的問題。緩存

Last-Modified/E-tag

Last-ModifiedE-tag的做用都是向服務器確認當前緩存文件是否爲最新。拋開功能不看,這兩個字段的表現以下:服務器

  • 若服務器在響應一個資源時添加了Last-Modified字段,那麼當下一次瀏覽器再一次向服務器請求該資源時(前提是瀏覽器中上一次的資源被緩存過了),會在請求header中包含If-Modified-Since字段,且值與服務器第一次響應給瀏覽器的Last-Modified字段一致
  • 若服務器在響應一個資源時添加了ETag字段,那麼當下一次瀏覽器再一次向服務器請求該資源時(前提是瀏覽器中上一次的資源被緩存過了),會在請求header中包含If-None-Match字段,且值與服務器第一次響應給瀏覽器的ETag字段一致

那麼上述是遵循了Http協議的瀏覽器會自動實現的,而要實現304的功能,就須要服務器(好比Apache對於靜態資源會自動實現這兩個字段的響應)或者咱們手動在服務器端編寫響應的邏輯來實現。

  • 若服務器在收到的資源請求中發現含有Last-Modified字段,則說明瀏覽器中包含了該資源的某一版本的緩存,此時服務器端將根據該字段的值進行必定的邏輯判斷,以決定讓瀏覽器直接使用已有的緩存(返回304)仍是將最新的文件發送過去(200,發送新文件並更新Last-Modified字段)
  • 若服務器在收到的資源請求中發現含有If-None-Matc字段,則說明瀏覽器中包含了該資源的某一版本的緩存,此時服務器端將根據該字段的值進行必定的邏輯判斷,以決定讓瀏覽器直接使用已有的緩存(返回304)仍是將最新的文件發送過去(200,發送新文件,並更新ETag

若同時使用了Last-ModifiedETag,正確的作法應該是當二者都符合條件時,才返回304

何時使用ETag?

Etag 主要爲了解決 Last-Modified 沒法解決的一些問題。

  • 一些文件也許會週期性的更改,可是他的內容並不改變(僅僅改變的修改時間),這個時候咱們並不但願客戶端認爲這個文件被修改了,而從新GET。這種狀況下能夠將某個能用來代表文件內容是否被更改的值(好比md5)來做爲ETag
  • 某些文件修改很是頻繁,好比在秒如下的時間內進行修改,(比方說1s內修改了N次),If-Modified-Since能檢查到的粒度是s級的,這種修改沒法判斷(或者說UNIX記錄MTIME只能精確到秒)
  • 某些服務器不能精確的獲得文件的最後修改時間

不一樣的頁面打開方式產生的請求區別

通常咱們打開(或者更新)一個頁面(或者資源)有幾種方式:

  • 在地址欄中輸入地址,而後回車
  • 激活當前頁面地址,而後回車
  • F5刷新頁面
  • 單機Back/Forward按鈕

上面幾種方式對資源的請求,會產生不一樣的結果,而且各瀏覽器的表現並不一致。具體的區別能夠參考鳥哥的《瀏覽器緩存機制

其中你們須要注意的一點是,刷新頁面(F5或者刷新按鈕),不論是否設置了max-age,都會從新像服務器發送請求。可是這不影響304邏輯。

實例代碼測試

nodejs寫了一個簡單的靜態文件服務器,用來測試上面的Cache-ControlLast-Modified,具體代碼能夠看gist

例子比較簡單,大致邏輯:

  • 每一個資源的200返回設置max-age=10,即緩存10秒。同時設置Last-Modified
  • 每次收到請求後,若發現包含if-modified-since字段,則304

測試過程和結果:

  • 第一次請求,不論是index.html仍是index.css均爲200,且response中包含了max-ageLast-Modified
  • 在地址欄中回車(10s之內),index.html304index.css200 ok ( from cache )
  • 若對頁面進行刷新( F5或者刷新頁面 ),二者均爲 304(在10s內或者不在10s內)

須要注意的問題:

  • index.html不論是否設置了max-age,都是304,同理,將index.css直接放到地址欄中請求也是304
  • index.css一次304以後的10s內又能繼續進行不須要請求服務器的直接本地緩存。這裏我我的認爲,瀏覽器的「直接使用本地緩存「的效果和從服務器成功200到數據產生的效果是一致的,除了文件自己,header字段等信息也是一樣會被cache的,所以304以後,max-age又能夠被繼續使用一遍。

作了nodejs的實驗以後,又開啓了apache服務器,一樣的將index.html和index.css文件放置到服務器根目錄中,請求後,發現apache默認已經作了Last-ModifiedETag的處理,而且在修改index.css文件後,能夠觀察到這兩個值的變化。

browser-cache

文章轉載:   http://blog.sina.com.cn/s/blog_4b32835b0101crcb.html

相關文章
相關標籤/搜索