今天小微開店寶在測試環境發佈更新的時候,同事問:「爲何我須要手動清理瀏覽器緩存才能看到變動?難道系統上線後也須要客戶本身清理瀏覽器緩存嗎!」看來,這個坑須要我來填了。前端
瀏覽器緩存(Brower Caching)
是瀏覽器在本地磁盤對用戶最近請求過的文檔進行存儲,當訪問者再次訪問同一頁面時,瀏覽器就能夠直接從本地磁盤加載文檔。web
瀏覽器緩存的優勢有:面試
在前端開發面試中,瀏覽器緩存是web性能優化面試題中很重要的一個知識點,從而說明瀏覽器緩存是提高web性能的一大利器,可是瀏覽器緩存若是使用不當,也會產生不少問題,正所謂是,想說愛你,並非很容易的事。因此,結合最近遇到的案例,本文對瀏覽器緩存相關的知識進行總結概括,但願對讀者有所幫助。瀏覽器
瀏覽器緩存主要有兩類:緩存協商
和完全緩存
,也有稱之爲協商緩存
和強緩存
。緩存
瀏覽器在第一次請求發生後,再次請求時:性能優化
expires
和cahe-control
判斷是否命中強緩存
,若命中則直接從緩存中獲取資源,包括緩存的header信息,本次請求不會與服務器進行通訊;強緩存是利用http的返回頭中的Expires
或者Cache-Control
兩個字段來控制的,用來表示資源的緩存時間。服務器
Expires
該字段是http1.0時的規範,它的值爲一個絕對時間的GMT格式的時間字符串,好比Expires:Mon,18 Oct 2066 23:59:59
GMT。這個時間表明着這個資源的失效時間,在此時間以前,即命中緩存。這種方式有一個明顯的缺點,因爲失效時間是一個絕對時間,因此當服務器與客戶端時間誤差較大時,就會致使緩存混亂。性能
Cache-Control
Cache-Control是http1.1時出現的header信息,主要是利用該字段的max-age
值來進行判斷,它是一個相對時間,例如Cache-Control:max-age=3600,表明着資源的有效期是3600秒。cache-control除了該字段外,還有下面幾個比較經常使用的設置值:測試
Cache-Control與Expires能夠在服務端配置同時啓用,同時啓用的時候Cache-Control優先級高。優化
協商緩存就是由服務器來肯定緩存資源是否可用,因此客戶端與服務器端要經過某種標識來進行通訊,從而讓服務器判斷請求資源是否能夠緩存訪問,這主要涉及到下面兩組header字段,這兩組搭檔都是成對
出現的,即第一次請求的響應頭帶上某個字段(Last-Modified
或者Etag
),則後續請求則會帶上對應的請求字段(If-Modified-Since
或者If-None-Match
),若響應頭沒有Last-Modified或者Etag字段,則請求頭也不會有對應的字段。
Last-Modify/If-Modify-Since
瀏覽器第一次請求一個資源的時候,服務器返回的header中會加上Last-Modify,Last-modify是一個時間標識該資源的最後修改時間,例如Last-Modify: Thu,31 Dec 2037 23:59:59 GMT。
當瀏覽器再次請求該資源時,request的請求頭中會包含If-Modify-Since,該值爲緩存以前返回的Last-Modify。服務器收到If-Modify-Since後,根據資源的最後修改時間判斷是否命中緩存。
若是命中緩存,則返回304,而且不會返回資源內容,而且不會返回Last-Modify。
ETag/If-None-Match
與Last-Modify/If-Modify-Since不一樣的是,Etag/If-None-Match返回的是一個校驗碼。ETag能夠保證每個資源是惟一的,資源變化都會致使ETag變化。服務器根據瀏覽器上送的If-None-Match值來判斷是否命中緩存。
與Last-Modified不同的是,當服務器返回304 Not Modified的響應時,因爲ETag從新生成過,response header中還會把這個ETag返回,即便這個ETag跟以前的沒有變化。
爲何要有Etag
你可能會以爲使用Last-Modified已經足以讓瀏覽器知道本地的緩存副本是否足夠新,爲何還須要Etag呢?HTTP1.1中Etag的出現主要是爲了解決幾個Last-Modified比較難解決的問題:
Last-Modified與ETag是能夠一塊兒使用的,服務器會優先驗證ETag,一致的狀況下,纔會繼續比對Last-Modified,最後才決定是否返回304。
強緩存與協商緩存的區別能夠用下表來表示:
|獲取資源形式|狀態碼|發送請求到服務器
------|------------|------|----------------
強緩存|從緩存取 |200(from cache)|否,直接從緩存取
協商緩存|從緩存取|304(Not Modified)|否,經過服務器來告知緩存是否可用
用戶操做 | Expires/Cache-Control | Last-Modied/Etag |
---|---|---|
地址欄回車 | 有效 | 有效 |
頁面連接跳轉 | 有效 | 有效 |
新開窗口 | 有效 | 有效 |
前進回退 | 有效 | 有效 |
F5刷新 | 無效 | 有效 |
Ctrl+F5強制刷新 | 無效 | 無效 |
如文章開頭所屬,代碼更新到線上後用戶瀏覽器不能自行更新,咱們不能要求客戶在系統更新後都進行一次緩存清理的操做。
到底該如何解決呢?
在資源請求的URL中增長一個參數,好比:js/mian.js?ver=0.7.1。這個參數是一個版本號,每一次部署的時候變動一下,當這個參數變化的時候,強緩存都會失效並從新加載。這樣一來,靜態資源,部署之後就須要從新加載。這樣就比較完美的解決了問題。
這樣作是否是最完美的呢?很遺憾,不是。
至於有什麼更好的方法,歡迎你們留言討論。