原文連接javascript
我的文章彙總在blogcss
緩存是一個很是重要一樣也很是複雜的瀏覽器特性html
在這篇文章中,咱們將解釋瀏覽器是如何利用緩存來使加載頁面更快,哪些因素決定了緩存的週期,在必要的時候如何去避開緩存。html5
全部的瀏覽器都會嘗試去緩存靜態資源的本地副本,以此去下降頁面的加載時間以及體積最小的網絡傳輸java
不論服務是在相同的網絡環境下仍是在世界上其餘的網絡環境下,從本地緩存中取資源必定會比經過網絡請求的方式要快git
瀏覽器針對此站點沒有任何的緩存文件,因此瀏覽器會向站點服務去請求全部所需的資源github
下面是一張首次訪問維基百科首頁的資源下載完以後的截圖,底部狀態欄顯示出有265kb的數據傳輸到了瀏覽器中web
瀏覽器會去請求站點服務器取到html頁面,而後會查看是否有對應靜態資源的緩存(js, css, images)chrome
當咱們從新刷新維基百科的頁面時,就能看出由於緩存的緣由與以前的請求情況不一樣的地方瀏覽器
此時數據的傳輸量已經降到了928bytes,至關於首頁訪問頁面時的0.3%,Size這一列就顯示出了咱們的大多數的資源都來自於緩存
Chrome即會在memory cache中去拉取內容,也會在disk cache中去拉取內容,由於在case1和case2中,咱們尚未關閉瀏覽器,因此數據依然會存儲在memory cache中
在chrome中,咱們能夠在地址欄中輸入chrome://cache去查看緩存的內容,對於每個已經緩存的文件,這裏都將會顯示一個頁面連接,頁面連接的內容包含一個更加詳細的視圖說明。
瀏覽器先去檢查服務器所生成的http響應頭信息,通常用於緩存相關的頭信息有4個:
ETag(Entity Tag)是一個用於緩存校驗token的字符串,它一般以文件的哈希值來表示
服務器能夠添加ETag到它的響應裏,瀏覽器接收到這個響應,那在將來的請求中(在文件過時以後),瀏覽器就能夠根據這個字段去判斷緩存中是否保留着一份過時的副本
若是經過對比hash值是相同的,那麼就說明這個資源沒有變化,服務器就會返回一個304狀態碼(Not Modified),瀏覽器就知道當前緩存的副本是安全的
注意:只有當緩存中的文件過時了,ETag纔會被用在請求中
Cache-Control頭擁有許多指令,利用這些指令咱們能夠設置緩存的行爲,過時時間,驗證等,同時這些也能夠組合起來一塊兒進行設置。
Cache-Control: public
複製代碼
public意味着資源能夠被任意緩存(瀏覽器,CDN等)
Cache-Control: private
複製代碼
private意味着資源只能被瀏覽器緩存
Cache-Control: no-store
複製代碼
no-store意味着讓瀏覽器老是去請求服務器以獲取資源
Cache-Control: no-cache
複製代碼
no-cache有一點誤導性,它並非說「不要緩存」
這是在告訴瀏覽器去緩存這個文件,但在和服務器確認最新版本以前不要去使用它。這個驗證的過程是經過ETag來完成的
這個行爲通常會用在html文件中,由於瀏覽器總會去檢查最新的html文件標識,因此這一點是講得通的
Cache-Control: max-age=60
複製代碼
這個指令指定了資源應該被緩存多少秒,因此max-age=60就意味着資源應該被緩存一分鐘,RFC 2616推薦這裏的最大值不要超過一年(max-age=31536000)
Cache-Control: s-max-age=60
複製代碼
這個指令僅僅是被用在中間緩存(好比CDN)
Cache-Control: must-revalidate
複製代碼
這個指令告訴緩存在使用它以前必須去驗證資源的過時狀態,若是已通過期就不該該被使用
Expires頭部來源於http1.0版本,可是在當今許多站點中依然保留着
這個頭部字段指定了一個日期,超過這個日期就表明資源是無效的
Expires: Wed, 25 Jul 2018 21:00:00 GMT
複製代碼
注意:若是已經指定了Cache-Control中的max-age指令,那瀏覽器就會忽略expires
Last-Modified頭部也是來自http1.0版本
Last-Modified: Mon, 12 Dec 2016 14:45:00 GMT
複製代碼
這個字段包含了資源最後修改的日期和時間
在HTML5版本以前,在html中使用元標籤(meta tag)制定cache-control是一個有效的方式
<meta http-equiv="Cache-control" content="no-cache">
複製代碼
但在html5中已經不推薦這麼作了,爲何?由於只有瀏覽器能夠識別這個標籤,而中間緩存(CDN)是識別不了的。
因此最好是都經過http頭的方式去發送緩存指令
讓咱們來看一個簡單的http響應
Accept-Ranges: bytes
Cache-Control: max-age=3600
Connection: Keep-Alive
Content-Length: 4361
Content-Type: image/png
Date: Tue, 25 Jul 2017 17:26:16 GMT
ETag: "1109-554221c5c8540"
Expires: Tue, 25 Jul 2017 18:26:16 GMT
Keep-Alive: timeout=5, max=93
Last-Modified: Wed, 12 Jul 2017 17:26:05 GMT
Server: Apache
複製代碼
因此咱們已經意識到緩存是個好東西,咱們應該積極利用它
可是咱們但願的是,不須要讓用戶每次都去刷新(Ctrl + F5)或者清空緩存才能看到咱們頁面的最新內容
這類緩存問題常常困擾者開發者以及用戶,用戶可能會看到一個錯亂的頁面或者是一個行爲怪異的按鈕,由於他們當前使用的已是過時的靜態資源文件
下面這張截圖描述了一個銀行網站的用戶與Chase Support之間的交流,能夠看到是有關登錄表單出了問題
該用戶頗有可能還在使用老的js文件,這就是致使點擊登錄按鈕是表單重置操做而不是表單提交操做
讓咱們來探索過時文件影響咱們的另一種狀況。
假設咱們在一個叫作app.min.js的文件中修復了一個bug,而且把它推送到了生產環境
在HTML中,該腳本是這個樣子
<script src="assets/js/app.min.js">
複製代碼
咱們的web服務器給這個js文件設置了max-age爲1周(604800秒)的過時時間
Cache-Control: private, max-age=604800
複製代碼
在更新完該js文件以後,一些用戶仍在反饋說那個bug依然存在。 那這裏到底發生了什麼呢?
在下一個章節中,咱們將會利用一個叫作"cache busting"的技術來解決這些問題和狀況
Cache busting會使一個資源文件失效,強制瀏覽器去服務器端從新獲取數據。
咱們能夠經過改變文件名來命令瀏覽器去避開緩存,對於瀏覽器來講,這是一份徹底新的資源,因此瀏覽器會去服務端請求最新的數據
Cache busting一樣容許咱們設置一個比較長的max-age值針對頻繁改動的資源。Google推薦max-age被設爲1年(source)
咱們能夠給文件名添加一個版本號
assets/js/app-v2.min.js
複製代碼
咱們能夠基於文件內容添加一個指紋值
assets/js/app-d41d8cd98f00b204e9800998ecf8427e.min.js
複製代碼
咱們能夠在文件名的末尾拼接一個查詢參數
assets/js/app.min.js?version=2
複製代碼
拼接查詢參數的方式在和代理服務器交互時有明顯的錯誤(known issues),因此這種方式通常不推薦使用
打開web開發者工具,在chrome中,這個信息會顯示在network面板中的Size列
使用下面的響應頭
Cache-Control: no-cache, no-store, must-revalidate
複製代碼
從chrome 66版本開始,chrome已經刪除了chrome://cache,緣由能夠參考reason1, reason2