場景1:
每次你開啟 XXXXHub,準備麒麟臂,滿心歡喜的等待一張圖片載入回來。圖片終於不負眾望載入回來了,可這居然是昨天看過的那張!這簡直大煞風景!誰能忍!
場景2:
有些時候,辦公室裡會傳來產品大人的尖叫:“怎麼網頁還是原來的樣子?” 然後你會聽到前端 GGMM 們不屑的回答:“我都說了,有快取”。 嗯,對的,網頁沒有改變,這是 HTTP 快取在起作用。因為瀏覽器在使用同樣的資源渲染網頁。
HTTP 快取讓前端 GG 們又愛又恨。 雖然 HTTP 快取在某些瞬間給前端 GGMM 們帶來了極大的痛苦(找不到 BUG),但很大程度上,快取也加速了人們鍛鍊麒麟臂的機會。
合理利用好 HTTP 快取,我能就能給每一位網頁瀏覽者 +1s。 下面我們一起來了解一下 HTTP 快取,揭開他神祕的面紗。
什麼是 HTTP 快取?
HTTP快取(或Web快取)是用於臨時儲存(快取)Web文件(如HTML頁面和影象),以減少伺服器延遲的一種資訊科技。HTTP快取系統會儲存下通過這套系統的文件的副本;如果滿足某些條件,則可以由快取滿足後續請求。HTTP快取系統既可以指裝置,也可以指計算機程式。
簡單來說,就是在開啟網頁的時候,將網頁中可能重複載入的資源,按照一定的規則儲存到本地,以便第二次開啟同樣的網站時,可以重複利用已有資源。
一個良好的快取策略,可以:
- 降低資源的重複載入
- 提高網頁的整體載入速度
- 節省使用者流量
- 給前端 GG 帶來痛苦(大霧
2 種快取機制
一般來說,會有兩種快取機制,分別是:協商快取和強快取。
假設資源 A 已經躺在了本地某個不知名角落裡。 現在,我們要再拿一次資源 A。
強快取——瀏覽器說了算
表現形式:
200 OK (from memory cache)
200 OK (from disk)
複製程式碼
瀏覽器發現本地資源 A 後,瀏覽器根據之前伺服器說下的驗身規則,給本地資源 A 驗明正身。
✅ 如果符合要求,瀏覽器會直接返回這個本地資源! ❌ 如果不符合要求,瀏覽器會想服務端發一個資源請求。
協商快取——伺服器說了算
命中後的表現形式:
304 Not Modified
複製程式碼
瀏覽器發現本地資源 A 後,瀏覽器給伺服器發了一個請求,將資源 A 相關的資訊告訴伺服器,問問伺服器本地的資源 A 還能不能用。
✅ 如果伺服器說還能用(返回 304),瀏覽器會直接返回本地資源 A。 ❌ 如果不符合要求,伺服器會直接返回一份完整的資源 A。
4 種快取策略
如果伺服器在頭部中配置了快取策略,那麼瀏覽器就會自動執行對應的邏輯了。
Expires
Expires: Wed, 11 May 2018 07:20:00 GMT
複製程式碼
這是來自 HTTP 1.0
的頭部內容。
他表示的是資源過期時間。在使用者對已快取資源發起第二次請求的時候,瀏覽器會將 Expires 對應的時間和本地時間比對。
P.S.:請求頭部帶上 Pragma: no-cache 會讓 Expires 失效。
✅ 沿用舊資源,返回 200 OK (from cache) ❌ 向服務端發起請求,要一個新資源
Cache-Control
Cache-Control: public, max-age=604800
複製程式碼
來自 HTTP 1.1
,是一個被廣泛使用的頭部欄位。
可以被用在請求頭部、響應頭部。
no-store
Cache-Control: no-store
複製程式碼
禁止使用快取。不允許將檔案快取到本地。
no-cache
Cache-Control: no-cache
複製程式碼
必須先與代理伺服器確認是否更改,然後再決定使用快取還是請求,類似於協商快取(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 = 使重新生效;使重新有法律效力。 意味著快取在考慮使用一個陳舊的資源時,必須先驗證它的狀態,已過期的快取將不被使用。
ETag && If-None-Match
快取的強校驗器(看檔案內容)
ETag
ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4"
ETag: W/"0815"
複製程式碼
來自響應頭部。 我們可以把 ETag 理解為資原始檔的指紋。 資源變化都會導致 ETag 變化,跟最後修改時間沒有關係,ETag 可以保證每一個資源是唯一的。 沒有明確指定生成ETag值的方法。 通常,使用內容的雜湊,最後修改時間戳的雜湊值,或簡單地使用版本號。 例如,MDN使用wiki內容的十六進位制數字的雜湊值。
If-None-Match
If-None-Match: "33a64df551425fcc55e4d42a148795d9f25f89d4"
複製程式碼
在請求資源的時候,瀏覽器會將它放在放在請求頭部。 一般來說,它的值,其實就是下載資源時響應頭部下發的 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 請求。 其實就是下載資源時響應頭部下發的 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,會怎樣?
告訴瀏覽器,必須發請求重新驗證資源。這時候會走協商快取機制。可能返回 200 或者 304
2、如果在 request/response header 中存在:cache-control: no-cache,會怎樣?
告訴瀏覽器,必須發請求重新驗證資源。這時候會走協商快取機制。
3、如果在 request/response header 中存在:cache-control: must-revalidate,會怎樣?
告訴瀏覽器,必須發請求重新驗證資源。這時候會走協商快取機制。
4、如果在 response header 中存在:Cache-Control: max-age=60, must-revalidate,會怎樣?
- 先來看看 must-revalidate 的定義:告訴瀏覽器、快取伺服器,本地副本過期前,可以使用本地副本;本地副本一旦過期,必須去源伺服器進行有效性校驗。
- 基於上面定義,可以知道這個頭部的執行操作是:如果資源在 60s 內再次訪問,可以直接返回強快取;如果超過 60s,則必須傳送網路請求到服務端,去驗證資源的有效性。
5、強快取 + 協商快取。強快取過期,協商快取返回 304,這時候頭部裡會帶上強快取的配置嗎?
看服務端是如何配置的。這個說不準。不過一般情況下, 會返回。
6、為什麼大廠都不怎麼用 etag?Yahoo的YSlow頁面分析工具為什麼推薦關閉 ETag?
- 大型網站多使用負載分擔的方式來排程HTTP請求,所以,同一個客戶端對同一個頁面的多次請求,很可能被分配到不同的伺服器來相應,而根據ETag的計算原理(計算引數包括inode,最後修改時間,和檔案大小),不同的伺服器,在其它所有方面都一樣的情況下,對於同一頁面也能夠計算出不同的ETag。因此,這時,雖然頁面沒有發生任何變化,但是伺服器還是會給出不同的ETag,重新傳送完整的頁面內容。這並不是我們希望發生的。
- 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:冬至到了,廣東的盆友注意防暑降溫!