博客 / 詳情

返回

前端工程師必懂知識點之HTTP緩存

為什麼要使用 HTTP 緩存
  • 對於資源:

假如每次請求的請求頭響應頭分別都是1k,請求文件大小是10k。那麼一次請求就是12k大小,n次就是(12 * n)k

  • 對於前端:

前端每次請求完畢都要重新渲染 影響用户體驗

  • 對於後端:

沒有緩存機制的話前端會頻繁的請求後端的接口。後端每次都要提供查找和下載等功能。如果請求基數比較大,服務器就會存在較大的壓力
為了減少網絡帶寬消耗、減少延遲與網絡阻塞,同時降低服務器壓力提高服務器性能

HTTP 緩存的內容是什麼
  • CSS JS 圖片等 更新頻率不大的靜態文件等
HTTP 緩存頭部字段
  • Cache-Control
存在於請求頭和響應頭中,是緩存控制字段
控制HTTP緩存的最高指令,緩存不緩存 它説了算
  • 相關value
no-store: 不緩存
no-cache: 緩存 但是前端使用緩存前 都會請求服務器 來判斷當前的緩存資源是否是最新 只是用不過期的緩存
max-age=x(單位秒):請求緩存後的x秒內 不再發起請求,HTTP1.1以上
s-maxage=x(單位秒):代理服務器請求源站後x秒內不再發起請求,只對CDN有效
public:客户端和代理服務器(CDN)都可以緩存
private:只有客户端可以緩存
Expires
  • 響應頭 代表資源過期時間,由服務器返回提供。但是瀏覽器端可以修改Expires。它是HTTP1.0的屬性,在與max-age共存的情況下,max-age的優先級較高(因為max-age是HTTP1.1的屬性)
  • 場景:
  1. 瀏覽器向服務器請求了一個a.js
  2. 服務器説:‘你煩不煩? 我們約定個時間Expires,時間還沒到就別來煩我了’。
  3. 然後服務器就返回了a.js和過期時間Expires
  4. 後續瀏覽器的請求 會先比對當前時間是否以及大於了Expires過去時間。如果還沒過期 就不會發起請求 使用緩存如果過期了 就會重新發起請求
  • 缺點:
可能時間過期了,但是重新發起請求後 發現當前資源a.js並沒有發現變化。這樣就造成了請求的浪費
  • 進階:
使用Last-ModifiedIf-Modified-Since
使服務器和瀏覽器之間在Expires的基礎上,增加一個羣文件最新修改時間來輔助判斷是否應該使用緩存
Last-Modified / if-Modified-Since
  • Last-Modified:響應頭 資源最新修改時間 由服務器告訴瀏覽器
  • if-Modified-Since:請求頭 資源最新修改時間 由瀏覽器告訴服務器。和Last-Modified是成對出現的,它們兩個會共同對比來決定這個文件要不要重新發送
  • 場景:
  1. 瀏覽器向服務器請求了一個a.js
  2. 服務器説:’你煩不煩? 我們約定個時間Expires,另外再給你一個文件最新修改時間Last-Modified,到時候時間到期了,我們就比對文件最新修改時間,對得上你就繼續使用緩存‘。
  3. 然後服務器就返回了a.js和過期時間Expires和文件最新修改時間Last-Modified
  4. 後續瀏覽器請求會先對比是否超過了Expires過期時間。沒過期就不發起請求,僅使用緩存。如果過期了 瀏覽器在後續請求服務器時就會帶上文件最新修改時間If-Modified-Since
  5. 服務器收到該請求後 會將Last-Modified 和 if-Modified-Since進行比對。
  6. 如果Last-Modified 和 if-Modified-Since不一樣,服務器就會去查找最新的a.js,同時會再次返回最新的a.jsExpiresLast-Modified
  7. 如果Last-Modified 和 if-Modified-Since一樣。服務器就會返回304 - Not-Modified,表示之前的緩存還可以繼續使用。
  • 缺點:
Expires不太穩定,瀏覽器端可以隨意的修改Expires
Last-Modified只能精確到秒。在極端情況下,假設文件在1s內發生了變動,那麼此時 Last-Modified 就無法感知到該文件的變化,這樣瀏覽器永遠都拿不到最新的文件資源。
  • 進階:
讓服務器和瀏覽器在過期時間Expiress + 最新修改時間Last-Modified 的基礎上,增加一個文件內容唯一對比標記Etagif-None-Match。而Expires不太穩定 再加入一個max-age來加以代替。
Etag / if-None-Match
  • Etag:響應頭,資源標識,由服務器告訴瀏覽器
  • if-None-Match:請求頭,資源緩存標識,由瀏覽器告訴服務器,其實就是上次服務器給瀏覽器的 Etag。和 Etag 是一對的,它們會進行對比(用法比 if-Modified-Since 更高級一些)
  • 場景:
  1. 瀏覽器向服務器發起了a.js的請求
  2. 服務器説:'你煩不煩? 我們約定個時間Expires,再給你一個max-age=60(秒)Last-Modified也給你,另外再給你一個文件內容唯一標識符Etag'。
  3. 然後服務器就返回了a.js和過期時間Expiresmax-age=60,和文件最新修改時間Last-Modified和文件內容唯一標識符Etag
  4. 後續瀏覽器在max-age=60秒內,就不會再次發起新的請求而是直接使用緩存。並且此時因為有了max-age的存在,Expires已經沒用了。
  5. 後續瀏覽器請求在max-age=60秒後,會攜帶上If-Modified-Since(服務器發送的Last-Modified) 和 if-None-Match(服務器發送的Etag)。
  6. 服務端會比對if-None-MatchEtag,儘管此時也傳遞了If-Modified-Since,但是服務端不會再對比if-Modified-SinceLast-Modified。因為Etag的優先級大於Last-ModifiedEtag更精準的解決了文件資源在1s內的變動問題

7.服務端比對後發現,if-None-Match 和 Etag不想等。説明a.js被修改過,服務器就會返回最新的a.js和全新的Etagmax-age,也會同時返回ExpiresLast-modified,雖然它倆已經沒什麼作用了。

  1. 服務端經對比發現,if-None-MatchEtag相等。説明a.js沒有任何變化,返回狀態碼304告訴瀏覽器 繼續使用之前的本地緩存
  • 缺點:
Expiresmax-age都沒有過期的情況下,瀏覽器是沒有辦法主動知道文件資源是否變動。因為在時間未到的情況下,瀏覽器肯定使用本地的緩存資源。
  • 進階:
這種問題在HTTP協議本身上來講,就很難解決了
    1. 通過 md5 / hash 緩存
通過不緩存 html,為靜態文件添加 md5 或者 hash 標識,來解決瀏覽器無法跳過緩存過期時間內主動感知文件變化的問題。
只需在項目每次發佈迭代的時候,給靜態文件添加不同的 md5/hash 標識即可。因為文件名並不一樣,服務端會認為是新的文件,所有跟各種緩存字段都沒有任何關係,也就不會存在緩存問題。
    1. 通過 CDN 緩存
CDN 是構建在網絡之上的內容分發網絡,依靠部署在各地的邊緣服務器,通過中心平台的負載均衡,內容分發,調度等功能模塊,使用户就近獲取所需內容,降低網絡阻塞,提高用户訪問響應速度和命中率,有一個字段是專門給 CDN 來使用的s-maxage=x(單位秒)
CDN 緩存的工作方式
  • 第一次請求
  1. 瀏覽器向服務器請求a.js資源。
  2. 服務端:'a.js這個文件我給我小弟 CDN 了,以後你要這個就找 CDN 吧,別找我了。
  3. 成功返回a.js給 CDN,CDN 進行緩存。同時 CDN 返回給瀏覽器瀏覽器自己也進行了緩存'。
  • 後續請求
  1. 瀏覽器緩存時間過期,再次發起請求時。這時候 服務器就不會理你了。此時CDN會幫你查找該資源,同時也分幾種情況:

1-1. CDN節點自己緩存的文件還沒有過期,CDN會打回該請求。返回狀態嗎304,告訴瀏覽器 之前的緩存資源還能使用。
1-2. CDN節點自己緩存的文件已經過期了。為了保險起見,CDN自己會發生請求到源服務器,成功拿回最新數據後,再返回給瀏覽器。

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.