看了這篇,關於瀏覽器緩存你還有哪些疑問?

【轉載請註明出處】:https://blog.csdn.net/huahao1989/article/details/107730210css

整個 Web 系統架構在HTTP 協議之上, 利用 HTTP 的緩存機制不只能夠極大地減小服務器負載, 更重要的是加速頁面的載入,以及減小用戶的流量消耗。 快速到達和易於訪問是 Web 與生俱來的特性, 其緩存機制也早已被服務器和瀏覽器廠商普遍地實現, 咱們做爲 Web 內容的做者何樂而不爲呢?算法

HTTP 緩存簡介

談起 HTTP 緩存你首先想到的必定是磁盤緩存,以及 304 狀態碼。 這是瀏覽器處理緩存的兩種狀況:後端

  • 瀏覽器詢問服務器緩存是否有效,服務器返回 304 指示瀏覽器使用緩存。
  • 資源仍然處於有效期時,瀏覽器會直接使用磁盤緩存(在刷新時稍有不一樣)。

image.png

每一個狀態的詳細說明以下:瀏覽器

一、Cache-Control

Cache-Control 在 HTTP 響應頭中,用於指示代理和 UA 使用何種緩存策略。好比:緩存

  • no-cache爲本次響應不可直接用於後續請求(在沒有向服務器進行校驗的狀況下)
  • no-store爲禁止緩存(不得存儲到非易失性介質,若是有的話儘可能移除,用於敏感信息)
  • private爲僅 UA 可緩存
  • public爲你們均可以緩存。

Cache-Control爲可緩存時,同時可指定緩存時間(好比public, max-age:86400)。 這意味着在 1 天(60x60x24=86400)時間內,瀏覽器均可以直接使用該緩存。 固然瀏覽器也有權隨時丟棄任何一項緩存,所以這裏可能有一致性問題。服務器

二、Etag

若是資源自己確實會隨時發生改動,還用 Cache-Control 就會使用戶看到的頁面得不到更新。 但若是還但願利用 HTTP 緩存,這就須要有條件的(conditional)HTTP 請求。架構

HTTP協議規格說明定義ETag爲「被請求變量的實體標記」,弱實體只要內容語義沒變便可,強實體指字節必須徹底一致,建議使用弱實體。負載均衡

若是響應體包含Etag字段,則瀏覽器在下次發送請求時會帶 If-None-Match 頭字段, 來詢問服務器該版本是否仍然可用。若是服務器發現該版本仍然是最新的, 就能夠返回 304 狀態碼指示 UA 繼續使用緩存。
相似服務器端返回的格式:
ETag: W/"3ae83efccfc543bad6866e325cd8bfb9" 分佈式

客戶端的查詢更新格式是這樣的:
If-None-Match:W/"3ae83efccfc543bad6866e325cd8bfb9"學習

若是ETag沒改變,則返回狀態304。

三、Last-Modified

在瀏覽器第一次請求某一個URL時,服務器端的返回狀態會是200,內容是請求的資源,同時有一個Last-Modified的屬性標記(HttpReponse Header)此文件在服務期端最後被修改的時間,格式相似這樣:
Last-Modified:Tue, 24 Feb 2009 08:01:04 GMT

客戶端第二次請求此URL時,根據HTTP協議的規定,瀏覽器會向服務器傳送If-Modified-Since報頭(HttpRequest Header),詢問該時間以後文件是否有被修改過:
If-Modified-Since:Tue, 24 Feb 2009 08:01:04 GMT

若是服務器端的資源沒有變化,則自動返回HTTP 304(NotChanged)狀態碼,內容爲空,這樣就節省了傳輸數據量。當服務器端代碼發生改變或者重啓服務器時,則從新發出資源,返回和第一次請求時相似。從而保證不向客戶端重複發出資源,也保證當服務器有變化時,客戶端可以獲得最新的資源。

注:若是If-Modified-Since的時間比服務器當前時間(當前的請求時間request_time)還晚,會認爲是個非法請求

四、Expires

給出的日期/時間後,被響應認爲是過期。如Expires:Thu, 02 Apr 2009 05:14:08 GMT

需和Last-Modified結合使用。用於控制請求文件的有效時間,當請求數據在有效期內時客戶端瀏覽器從緩存請求數據而不是服務器端。當緩存中數據失效或過時,才決定從服務器更新數據。

五、Last-Modified和Expires

Last-Modified標識可以節省一點帶寬,可是仍是逃不掉髮一個HTTP請求出去,並且要和Expires一塊兒用。而Expires標識卻使得瀏覽器乾脆連HTTP請求都不用發,好比當用戶F5或者點擊Refresh按鈕的時候就算對於有Expires的URI,同樣也會發一個HTTP請求出去,因此,Last-Modified仍是要用的,並且要和Expires一塊兒用。

六、Etag和Expires

若是服務器端同時設置了Etag和Expires時,Etag原理一樣,即與Last-Modified/Etag對應的HttpRequestHeader:If-Modified-Since和If-None-Match。咱們能夠看到這兩個Header的值和WebServer發出的Last-Modified, Etag值徹底同樣;在徹底匹配If-Modified-Since和If-None-Match即檢查完修改時間和Etag以後,服務器才能返回304.

七、Last-Modified和Etag

分佈式系統裏多臺機器間文件的last-modified必須保持一致,以避免負載均衡到不一樣機器致使比對失敗

分佈式系統儘可能關閉掉Etag(每臺機器生成的etag都會不同)

Last-Modified和ETags請求的http報頭一塊兒使用,服務器首先產生Last-Modified/Etag標記,服務器可在稍後使用它來判斷頁面是否已經被修改,來決定文件是否繼續緩存

過程以下:

  1. 客戶端請求一個頁面(A)。
  2. 服務器返回頁面A,並在給A加上一個Last-Modified/ETag。
  3. 客戶端展示該頁面,並將頁面連同Last-Modified/ETag一塊兒緩存。
  4. 客戶再次請求頁面A,並將上次請求時服務器返回的Last-Modified/ETag一塊兒傳遞給服務器。
  5. 服務器檢查該Last-Modified或ETag,並判斷出該頁面自上次客戶端請求以後還未被修改,直接返回響應304和一個空的響應體。

注:

  1. Last-Modified和Etag頭都是由WebServer發出的HttpReponse Header,WebServer應該同時支持這兩種頭。
  2. WebServer發送完Last-Modified/Etag頭給客戶端後,客戶端會緩存這些頭;
  3. 客戶端再次發起相同頁面的請求時,將分別發送與Last-Modified/Etag對應的HttpRequestHeader:If-Modified-Since和If-None-Match。這兩個Header的值和WebServer發出的Last-Modified,Etag值徹底同樣;
  4. 經過上述值到服務器端檢查,判斷文件是否繼續緩存;
八、關於 Cache-Control: max-age=秒 和 Expires

Expires = 時間,HTTP 1.0 版本,緩存的載止時間,容許客戶端在這個時間以前不去檢查(發請求)
max-age = 秒,HTTP 1.1版本,資源在本地緩存多少秒。
若是max-age和Expires同時存在,則被Cache-Control的max-age覆蓋。

Expires 的一個缺點就是,返回的到期時間是服務器端的時間,這樣存在一個問題,若是客戶端的時間與服務器的時間相差很大,那麼偏差就很大,因此在HTTP 1.1版開始,使用Cache-Control: max-age=秒替代。

Expires =max-age + 「每次下載時的當前的request時間」

因此一旦從新下載的頁面後,expires就從新計算一次,但last-modified不會變化

九、瀏覽器刷新

正常從新加載

按下刷新按鈕或快捷鍵(在 MacOS 中是 Cmd+R)會觸發瀏覽器的「正常從新加載」(normal reload), 此時瀏覽器會執行一次 Conditional GET。 Cache-Control 等緩存頭字段會被忽略,而且帶If-None-Match, If-Modified-Since等頭字段。 此時服務器總會收到一次 HTTP GET 請求。 在 Chrome 中按下刷新,瀏覽器還會帶以下請求頭:
Cache-Control:max-age=0

注意:在地址欄從新輸入當前頁面地址並按下回車也會當作刷新處理, 這意味着只有重新標籤頁或超連接打開時,才能觀察到直接使用硬盤緩存的狀況。

強制從新加載

在 Chrome 中按下 Cmd+Shift+R (MacOS)能夠觸發強制從新加載(Hard Reload), 此時包括頁面自己在內的全部資源都不會使用緩存。 瀏覽器直接發送 HTTP 請求且不帶任何條件請求字段。 在 Chrome 中強制刷新,瀏覽器還會帶以下請求頭:
Cache-Control: no-cache
Pragma: no-cache

如何讓緩存的靜態文件失效

通常咱們在頁面上引用不少js或者css文件,一旦請求過而且緩存在瀏覽器中的資源並無失效,這個時候發現咱們有個bug須要修改或者有新的東西須要發佈,你要怎麼辦?有些人就說了,強制刷新下瀏覽器就行了,或者在請求的時候不返回304,直接返回新的資源內容,可是這樣並很差操做,一是用戶未必知道強制刷新或者清理緩存,二是咱們只想在發佈新的內容以後第一次用戶的請求返回新的內容並緩存,後面仍是走緩存;三是咱們通常都會使用CDN,每次發佈完以後還須要清理CDN緩存,非常麻煩。其實有一個最簡單的辦法就是在引用這些靜態資源的時候加一個版本號便可,相似.../js/index.js?v=1.0這樣的,若是修改了內容,那麼只須要改一下版本號便可,瀏覽器天然會獲取到新的內容。

歡迎關注 「後端老鳥」 公衆號,接下來會發一系列的專題文章,包括Java、Python、Linux、SpringBoot、SpringCloud、Dubbo、算法、技術團隊的管理等,還有各類腦圖和學習資料,NFC技術、搜索技術、爬蟲技術、推薦技術、音視頻互動直播等,只要有時間我就會整理分享,敬請期待,現成的筆記、腦圖和學習資料若是你們有需求也能夠公衆號留言提早獲取。因爲本人在全部團隊中基本都處於攻堅和探路的角色,搞過的東西多,遇到的坑多,解決的問題也不少,歡迎你們加公衆號進羣一塊兒交流學習。

【轉載請註明出處】:https://blog.csdn.net/huahao1989/article/details/107730210

相關文章
相關標籤/搜索