了解HTTP協(xié)議的前端同學(xué),相比對Cache-Control不會感到陌生,性能優(yōu)化時經(jīng)常都會跟它打交道。常見的值有有private、public、no-store、no-cache、must-revalidate、max-age等。網(wǎng)上總結(jié)挺多的,但是,系統(tǒng)好理解確實很少
瀏覽器緩存機制
在說這個服務(wù)如何寫之前我們先要明白瀏覽器緩存到底是個啥。來看下這個簡略示意圖:

可以看到瀏覽器的緩存機制分為兩個部分。1、當前緩存是否過期?2、服務(wù)器中的文件是否有改動?
第一步:判斷當前緩存是否過期
這是判斷是否啟用緩存的第一步。如果瀏覽器通過某些條件(條件之后再說)判斷出來,ok現(xiàn)在這個緩存沒有過期可以用,那么連請求都不會發(fā)的,直接是啟用之前瀏覽器緩存下來的那份文件:

中看到這個css文件緩存沒有過期,被瀏覽器直接通過緩存讀取了出來,注意這個時候是不會向瀏覽器請求的! 如果過期了就會向服務(wù)器重新發(fā)起請求,但是不一定就會重新拉取文件!
第二步:判斷服務(wù)器中的文件是否有改動
1、緩存過期,文件有改動
如果服務(wù)器發(fā)現(xiàn)這個文件改變了那么你肯定不能再用以前瀏覽器的緩存了,那就返回個200并且?guī)闲碌奈募?/p>

2、緩存過期,文件無改動
同時如果發(fā)現(xiàn)雖然那個緩存雖然過期了,可你在服務(wù)器端的文件沒有變過,那么服務(wù)器只會給你返回一個頭信息(304),讓你繼續(xù)用你那過期的緩存,這樣就節(jié)省了很多傳輸文件的時間帶寬啥的??聪聢D:

過期了的緩存需要請求一次服務(wù)器,若服務(wù)器判斷說這個文件沒有改變還能用,那就返回304。瀏覽器認識304,它就會去讀取過期緩存。否則就真的傳一份新文件到瀏覽器。
如何判斷緩存的過期以及文件的變動?
在剛才的敘述中作者沒有提到具體的判斷過期及變動的實現(xiàn)方式,這也是為了可以讓童鞋們現(xiàn)有一個整體的概念,無關(guān)乎代碼,至少通過上面一段講述,可以認識到“哦瀏覽器的緩存是這樣一個流程”,就夠了。下面我們來看下具體的如何操作:
判斷緩存過期
主要的方式有兩種,這兩種都是設(shè)定請求頭中的某一個字段來實現(xiàn)的:1、Expires;2、Cache-Control。由于Cache-Control設(shè)置后優(yōu)先級比前者高,這次作者就先說下通過Cache-Control來控制緩存。

no-cache
如果request headers中,Cache-Control為no-cache。表示不管服務(wù)端有沒有設(shè)置Cache-Control,都必須從重新去獲取請求。
max-age=0
max-age=0表示不管response怎么設(shè)置,在重新獲取資源之前,先檢驗ETag/Last-Modified
不管是max-age=0還是no-cache,都會返回304(資源無修改的情況下),no-store才是真正的不進行緩存。
判斷文件變動
常用的方式為Etag和Last-Modified,思路上差不多,這里作者只介紹Last-Modified的用法。
Last-Modified方式需要用到兩個字段:Last-Modified & if-modified-since。
先來看下這兩個字段的形式:
Last-Modified : Fri , 12 May 2006 18:53:33 GMT
If-Modified-Since : Fri , 12 May 2006 18:53:33 GMT
可以看出其實形式是一樣的,就是一個標準時間。那么怎么用呢?來看下圖:

當?shù)谝淮握埱竽骋粋€文件的時候,就會傳遞回來一個Last-Modified 字段,其內(nèi)容是這個文件的修改時間。當這個文件緩存過期,瀏覽器又向服務(wù)器請求這個文件的時候,會自動帶一個請求頭字段If-Modified-Since,其值是上一次傳遞過來的Last-Modified的值,拿這個值去和服務(wù)器中現(xiàn)在這個文件的最后修改時間做對比,如果相等,那么就不會重新拉取這個文件了,返回304讓瀏覽器讀過期緩存。如果不相等就重新拉取。
Cache-Control與Expires
Cache-Control與Expires的作用一致,都是指明當前資源的有效期,控制瀏覽器是否直接從瀏覽器緩存取數(shù)據(jù)還是重新發(fā)請求到服務(wù)器取數(shù)據(jù)。只不過Cache-Control的選擇更多,設(shè)置更細致,如果同時設(shè)置的話,其優(yōu)先級高于Expires。
Last-Modified/ETag與Cache-Control/Expires
配置Last-Modified/ETag的情況下,瀏覽器再次訪問統(tǒng)一URI的資源,還是會發(fā)送請求到服務(wù)器詢問文件是否已經(jīng)修改,如果沒有,服務(wù)器會只發(fā)送一個304回給瀏覽器,告訴瀏覽器直接從自己本地的緩存取數(shù)據(jù);如果修改過那就整個數(shù)據(jù)重新發(fā)給瀏覽器;
Cache-Control/Expires則不同,如果檢測到本地的緩存還是有效的時間范圍內(nèi),瀏覽器直接使用本地副本,不會發(fā)送任何請求。兩者一起使用時,Cache-Control/Expires的優(yōu)先級要高于Last-Modified/ETag。即當本地副本根據(jù)Cache-Control/Expires發(fā)現(xiàn)還在有效期內(nèi)時,則不會再次發(fā)送請求去服務(wù)器詢問修改時間(Last-Modified)或?qū)嶓w標識(Etag)了。
一般情況下,使用Cache-Control/Expires會配合Last-Modified/ETag一起使用,因為即使服務(wù)器設(shè)置緩存時間, 當用戶點擊“刷新”按鈕時,瀏覽器會忽略緩存繼續(xù)向服務(wù)器發(fā)送請求,這時Last-Modified/ETag將能夠很好利用304,從而減少響應(yīng)開銷。
Last-Modified與ETag
你可能會覺得使用Last-Modified已經(jīng)足以讓瀏覽器知道本地的緩存副本是否足夠新,為什么還需要Etag(實體標識)呢?HTTP1.1中Etag的出現(xiàn)主要是為了解決幾個Last-Modified比較難解決的問題:
Last-Modified標注的最后修改只能精確到秒級,如果某些文件在1秒鐘以內(nèi),被修改多次的話,它將不能準確標注文件的新鮮度
如果某些文件會被定期生成,當有時內(nèi)容并沒有任何變化,但Last-Modified卻改變了,導(dǎo)致文件沒法使用緩存
有可能存在服務(wù)器沒有準確獲取文件修改時間,或者與代理服務(wù)器時間不一致等情形
Etag是服務(wù)器自動生成或者由開發(fā)者生成的對應(yīng)資源在服務(wù)器端的唯一標識符,能夠更加準確的控制緩存。Last-Modified與ETag是可以一起使用的,服務(wù)器會優(yōu)先驗證ETag,一致的情況下,才會繼續(xù)比對Last-Modified,最后才決定是否返回304。Etag的服務(wù)器生成規(guī)則和強弱Etag的相關(guān)內(nèi)容可以參考,《互動百科-Etag》和《HTTP Header definition》,這里不再深入。
用戶操作行為與緩存
用戶在使用瀏覽器的時候,會有各種操作,比如輸入地址后回車,按F5刷新等,這些行為會對緩存有什么影響呢?
