場景1:
每次你打開 XXXXHub,準備麒麟臂,滿心歡喜的等待一張圖片加載回來。圖片終于不負眾望加載回來了,可這居然是昨天看過的那張!這簡直大煞風景!誰能忍!
場景2:
有些時候,辦公室里會傳來產品大人的尖叫:“怎么網(wǎng)頁還是原來的樣子?”
然后你會聽到前端 GGMM 們不屑的回答:“我都說了,有緩存”。
嗯,對的,網(wǎng)頁沒有改變,這是 HTTP 緩存在起作用。因為瀏覽器在使用同樣的資源渲染網(wǎng)頁。
HTTP 緩存讓前端 GG 們又愛又恨。
雖然 HTTP 緩存在某些瞬間給前端 GGMM 們帶來了極大的痛苦(找不到 BUG),但很大程度上,緩存也加速了人們鍛煉麒麟臂的機會。
合理利用好 HTTP 緩存,我能就能給每一位網(wǎng)頁瀏覽者 +1s。
下面我們一起來了解一下 HTTP 緩存,揭開他神秘的面紗。
什么是 HTTP 緩存?
HTTP緩存(或Web緩存)是用于臨時存儲(緩存)Web文檔(如HTML頁面和圖像),以減少服務器延遲的一種信息技術。HTTP緩存系統(tǒng)會保存下通過這套系統(tǒng)的文檔的副本;如果滿足某些條件,則可以由緩存滿足后續(xù)請求。HTTP緩存系統(tǒng)既可以指設備,也可以指計算機程序。
簡單來說,就是在打開網(wǎng)頁的時候,將網(wǎng)頁中可能重復加載的資源,按照一定的規(guī)則保存到本地,以便第二次打開同樣的網(wǎng)站時,可以重復利用已有資源。
一個良好的緩存策略,可以:
- 降低資源的重復加載
- 提高網(wǎng)頁的整體加載速度
- 節(jié)省用戶流量
- 給前端 GG 帶來痛苦(大霧
2 種緩存機制


一般來說,會有兩種緩存機制,分別是:協(xié)商緩存和強緩存。
假設資源 A 已經躺在了本地某個不知名角落里。
現(xiàn)在,我們要再拿一次資源 A。
強緩存——瀏覽器說了算
表現(xiàn)形式:
200 OK (from memory cache)
200 OK (from disk)
瀏覽器發(fā)現(xiàn)本地資源 A 后,瀏覽器根據(jù)之前服務器說下的驗身規(guī)則,給本地資源 A 驗明正身。
? 如果符合要求,瀏覽器會直接返回這個本地資源!
? 如果不符合要求,瀏覽器會想服務端發(fā)一個資源請求。
協(xié)商緩存——服務器說了算
命中后的表現(xiàn)形式:
304 Not Modified
瀏覽器發(fā)現(xiàn)本地資源 A 后,瀏覽器給服務器發(fā)了一個請求,將資源 A 相關的信息告訴服務器,問問服務器本地的資源 A 還能不能用。
? 如果服務器說還能用(返回 304),瀏覽器會直接返回本地資源 A。
? 如果不符合要求,服務器會直接返回一份完整的資源 A。
4 種緩存策略

如果服務器在頭部中配置了緩存策略,那么瀏覽器就會自動執(zhí)行對應的邏輯了。
Expires
Expires: Wed, 11 May 2018 07:20:00 GMT
這是來自 HTTP 1.0 的頭部內容。
他表示的是資源過期時間。在用戶對已緩存資源發(fā)起第二次請求的時候,瀏覽器會將 Expires 對應的時間和本地時間比對。
P.S.:請求頭部帶上 Pragma: no-cache 會讓 Expires 失效。
? 沿用舊資源,返回 200 OK (from cache)
? 向服務端發(fā)起請求,要一個新資源
Cache-Control

Cache-Control: public, max-age=604800
來自 HTTP 1.1,是一個被廣泛使用的頭部字段。
可以被用在請求頭部、響應頭部。
no-store
Cache-Control: no-store
禁止使用緩存。不允許將文件緩存到本地。
no-cache
Cache-Control: no-cache
必須先與代理服務器確認是否更改,然后再決定使用緩存還是請求,類似于協(xié)商緩存(304)
public
Cache-Control: public
可以被所有用戶緩存(多用戶共享),包括終端和CDN等中間代理服務器
一般搭配其他 cache-control 配置一同使用。
private
Cache-Control: private
與 public 屬性相反,private 意味著:
資源只能被終端瀏覽器緩存(而且是私有緩存),不允許中繼緩存服務器進行緩存。
一般搭配其他 cache-control 配置一同使用。
max-age
Cache-Control: max-age=31536000
告訴瀏覽器資源多久之內有效。在這個有效期之內,瀏覽器會直接返回已經存在本地的資源。
是一個經典的緩存過期機制。
s-maxage
Cache-Control: max-age=3600
覆蓋max-age 或者 Expires 頭,但是僅適用于共享緩存(比如各個代理),并且私有緩存中它被忽略。
must-revalidate
Cache-Control: must-revalidate
revalidate = 使重新生效;使重新有法律效力。
意味著緩存在考慮使用一個陳舊的資源時,必須先驗證它的狀態(tài),已過期的緩存將不被使用。
ETag && If-None-Match
緩存的強校驗器(看文件內容)

ETag
ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4"
ETag: W/"0815"
來自響應頭部。
我們可以把 ETag 理解為資源文件的指紋。
資源變化都會導致 ETag 變化,跟最后修改時間沒有關系,ETag 可以保證每一個資源是唯一的。
沒有明確指定生成ETag值的方法。 通常,使用內容的散列,最后修改時間戳的哈希值,或簡單地使用版本號。 例如,MDN使用wiki內容的十六進制數(shù)字的哈希值。
If-None-Match
If-None-Match: "33a64df551425fcc55e4d42a148795d9f25f89d4"
在請求資源的時候,瀏覽器會將它放在放在請求頭部。
一般來說,它的值,其實就是下載資源時響應頭部下發(fā)的 ETag。
Last-Modified && If-Modified-Since
一個緩存的弱校驗器(精確度比 ETag 要低)。

Last-Modified
Last-Modified: Wed, 21 Oct 2015 07:28:00 GMT
一個響應頭部。
包含源頭服務器認定的資源做出修改的日期及時間。
瀏覽器會將 Last-Modified 與資源綁定在一起。
它通常被用作一個驗證器來判斷接收到的或者存儲的資源是否彼此一致。
If-Modified-Since
If-Modified-Since: Wed, 21 Oct 2015 07:28:00 GMT
一個請求頭部。一般用在 GET 請求。
其實就是下載資源時響應頭部下發(fā)的 Last-Modified。
服務器收到請求后,會比較:當前資源的修改時間和 If-Modified-Since。
? 當前資源修改時間 <= If-Modified-Since
意味著資源在 If-Modified-Since 這個時間點之后沒有被改動,返回 304 + 空包。? 當前資源修改時間 > If-Modified-Since
意味著資源在 If-Modified-Since 這個時間點之后改動了,返回 200 + 完整資源。
主流搭配
Cache-Control: max-age + expires + last-modified
測試題
概念我們已經看完了,又長又臭。如果這時候不來點測試題,那么很快你又會把它忘光了。下面我為你準備了幾道簡單的題目,目的是讓你能更好的記住緩存的相關概念,而且也知道他們是怎么應用的。
1、如果在 request/response header 中存在:cache-control: max-age=0,會怎樣?
告訴瀏覽器,必須發(fā)請求重新驗證資源。這時候會走協(xié)商緩存機制??赡芊祷?200 或者 304
2、如果在 request/response header 中存在:cache-control: no-cache,會怎樣?
告訴瀏覽器,必須發(fā)請求重新驗證資源。這時候會走協(xié)商緩存機制。
3、如果在 request/response header 中存在:cache-control: must-revalidate,會怎樣?
告訴瀏覽器,必須發(fā)請求重新驗證資源。這時候會走協(xié)商緩存機制。
4、如果在 response header 中存在:Cache-Control: max-age=60, must-revalidate,會怎樣?
- 先來看看 must-revalidate 的定義:告訴瀏覽器、緩存服務器,本地副本過期前,可以使用本地副本;本地副本一旦過期,必須去源服務器進行有效性校驗。
- 基于上面定義,可以知道這個頭部的執(zhí)行操作是:如果資源在 60s 內再次訪問,可以直接返回強緩存;如果超過 60s,則必須發(fā)送網(wǎng)絡請求到服務端,去驗證資源的有效性。
5、強緩存 + 協(xié)商緩存。強緩存過期,協(xié)商緩存返回 304,這時候頭部里會帶上強緩存的配置嗎?
看服務端是如何配置的。這個說不準。不過一般情況下, 會返回。
6、為什么大廠都不怎么用 etag?Yahoo的YSlow頁面分析工具為什么推薦關閉 ETag?
- 大型網(wǎng)站多使用負載分擔的方式來調度HTTP請求,所以,同一個客戶端對同一個頁面的多次請求,很可能被分配到不同的服務器來相應,而根據(jù)ETag的計算原理(計算參數(shù)包括inode,最后修改時間,和文件大?。?,不同的服務器,在其它所有方面都一樣的情況下,對于同一頁面也能夠計算出不同的ETag。因此,這時,雖然頁面沒有發(fā)生任何變化,但是服務器還是會給出不同的ETag,重新發(fā)送完整的頁面內容。這并不是我們希望發(fā)生的。
- ETag的計算占用服務器的CPU資源。
7、cache-control:max-age + etag + last-modified + expires,判斷順序是什么?
- 如果expires和cache-control同時存在,cache-control會覆蓋expires。
- 建議兩個都寫,cache-control是http1.1的頭字段,expires是http1.0的頭字 段,都寫兼容會好點。
8、s-maxage 和 max-age 同時配置,會有什么效果?
- max-age 給客戶端用,s-maxage 給代理服務器用
- s-maxage 一般配置一個比 max-age 要更小一些的值,避免代理服務器直接使用 max-age,將文件緩存太久
結語
看完了這又長又臭的文章之后,相信你對 HTTP 緩存會有一個更深入的了解。如果你還有什么不懂的話,歡迎留言,我會盡我所能解答你的~~
BTW:冬至到了,廣東的盆友注意防暑降溫!