瀏覽器快取篇

zimo發表於2017-09-17

前言

在前端開發中,快取有利於加快網頁的載入速度,同時快取能夠被反覆利用,所以可以減少流量和頻寬的開銷。

快取的分類有很多種,CDN快取、資料庫快取、代理伺服器快取和瀏覽器快取。本篇將來講解一下Web開發中的瀏覽器快取。這個在實際開發環境中往往也會被問到,或者使用到。如何去準確認清楚快取的概念,是前端必須要去學習的。如果你喜歡我的文章,歡迎評論,歡迎Star~。歡迎關注我的github部落格

正文

瀏覽器的快取問題,主要指的是http的快取——即協議層。而h5新增的storage和資料庫快取,那是應用層快取,並不被計入本篇的分析內容裡面。下面我們正式開始來進行快取的分析。

協議層的快取,其實,可以被分成強制快取和對比快取。

強制快取

首先,我們先來看一張強制快取時的時序圖,來了解一下強制快取在不同情況下的請求模式:

force cache
force cache

從圖中,我們不難看出,只有當快取失效時,才會去伺服器獲取最新資源的方式,就是強制快取。而在協議層的欄位中,可以造成強制快取的欄位有兩個Expires和Cache-Control。

1.0的時候見到我——Expires

最早使用的是Expires欄位,該欄位表示快取到期時間,即有效時間+當時伺服器的時間,然後將這個時間設定在header中返回給伺服器。因此,該時間是一個絕對時間,舉例說明:

Expires: Thu, 10 Nov 2017 08:45:11 GMT複製程式碼

圖片示例:

expires
expires

在響應訊息頭中,設定這個欄位之後,就可以告訴瀏覽器,在未過期之前不需要再次請求。

但是,這個欄位設定時有缺點

由於是絕對時間,使用者可能會將客戶端本地的時間進行修改,而導致瀏覽器判斷快取失效,重新請求該資源,同時,還導致客戶端與服務端的時間不一致,致使快取失效。

1.1的時候我來了——Cache-Control

已知Expires的缺點之後,在HTTP/1.1中,增加了一個欄位Cache-Control,該欄位表示資源快取的最大有效時間,在該時間內,客戶端不需要向伺服器傳送請求

這兩者的區別就是前者是絕對時間,而後者是相對時間。我們不妨舉個例子來說明一下:

Cache-Control: max-age=2592000複製程式碼

圖片示例:

Cache-Control
Cache-Control

下面列舉一下Cache-Control的欄位可以帶的值:

  1. max-age:即最大有效時間,在上面的例子中我們可以看到

  2. no-cache:表示沒有快取,即告訴瀏覽器該資源並沒有設定快取

  3. s-maxage:同max-age,但是僅用於共享快取,如CDN快取

  4. public:多使用者共享快取,預設設定

  5. private:不能夠多使用者共享,HTTP認證之後,欄位會自動轉換成private。

總結一下,自從http1.1開始,Expires逐漸被Cache-Control取代。Cache-Control是一個相對時間,即使客戶端時間發生改變,相對時間也不會隨之改變,這樣可以保持伺服器和客戶端的時間一致性。而且Cache-Control的可配置性比較強大。

對比快取

扯完強制快取,我們來看看對比快取。在解釋這個之前,是否可以先猜想一下,強制快取是,快取在未過有效期時,不需要請求資源。那麼,對比快取的原理又該如何呢?

廢話不多說,我們也先從對比快取的時序圖講起,如圖:

compare cache
compare cache

對比快取的過程是,先從快取中獲取對應的資料標識,然後向伺服器傳送請求,確認資料是否更新,如果更新,則返回新資料和新快取;反之,則返回304狀態碼,告知客戶端快取未更新,可繼續使用。

這正好彌補了一些強制快取的缺陷。對比快取主要應用於一些時常需要動態更新的資原始檔。

對比快取在協議裡的欄位是Last-Modified和If-Modified-Since。

別人的好夥伴——Last-Modified

Last-Modified:伺服器告知客戶端,資源最後一次被修改的時間,例如

Last-Modified: Thu, 10 Nov 2015 08:45:11 GMT複製程式碼

last-modified
last-modified

If-Modified-Since:再次請求時,請求頭中帶有該欄位,伺服器會將If-Modified-Since的值與Last-Modified欄位進行對比,如果相等,則表示未修改,響應304;反之,則表示修改了,響應200狀態碼,返回資料。

這個欄位可以和Cache-Control配合使用。

但是他還是有一定缺陷的:

  1. 如果資源更新的速度是秒以下單位,那麼該快取是不能被使用的,因為它的時間單位最低是秒。

  2. 如果檔案是通過伺服器動態生成的,那麼該方法的更新時間永遠是生成的時間,儘管檔案可能沒有變化,所以起不到快取的作用。

我來完善它——Etag

由於Last-modified還是存在缺陷的,儘管大多數情況下,會使用它,但當遇到我們上面所說的場景時,我們可能就需要了解一下,我們另一個小夥伴了——Etag。

Etag儲存的是檔案的特殊標識(一般都是hash生成的),伺服器儲存著檔案的Etag欄位,可以在與每次客戶端傳送If-no-match的欄位進行比較,如果相等,則表示未修改,響應304;反之,則表示已修改,響應200狀態碼,返回資料。

最後,通過一張原理圖,我們來加深一下記憶:

etag
etag

至此為止,兩種快取型別的快取方式已經闡述完成了,不知你是否已經心中已經有個大致的印象,當別人問起時,你可以對答如流。希望我們一同進步吧,fighting。

瀏覽器行為引起的不同

最後,我們來聊聊瀏覽器行為會引起快取的變化吧。

下面說一下瀏覽器的行為會產生怎樣的請求:

  1. 重新整理網頁 => 如果快取沒有失效,瀏覽器會直接使用快取;反之,則向伺服器請求資料
  2. 手動重新整理(F5) => 瀏覽器會認為快取失效,在請求伺服器時加上Cache-Control: max-age=0欄位,然後詢問伺服器資料是否更新。
  3. 強制重新整理(Ctrl + F5) => 瀏覽器會直接忽略快取,在請求伺服器時加上Cache-Control: no-cache欄位,然後重新向伺服器拉取檔案。

移動端的快取處理

在PC端或許這樣子的快取機制就已經足夠了,因為PC端不需要為網路的問題擔心。

但是,移動端卻不行,任何一個網路請求的增加,對於移動端的載入消耗時間都是比較大的(誰叫移動端的網太差呢,3G、2G)。那麼,上述的快取有什麼問題呢?其實,強制快取是沒有太大問題的,因為只要快取不到期,是不會想伺服器傳送請求的;但是如果是對比快取的情況下,304的問題就比較巨大,因為它會造成無用的請求。每次在使用快取前,都會向伺服器傳送請求確認,導致網路的延時。

一次完美的快取必須保證兩點:

  1. 資料快取之後,儘量減少伺服器的請求
  2. 如果資源更新的話,必須使得客戶端的資源一起更新。

所以,一般我們會運用的方式是:

在資原始檔後面加上表示,如config.f1ec3.js、config.v1.js之類的,然後給資源設定較長的快取時間,如一年

Cache-Control: max-age=31536000複製程式碼

這樣子,就不會造成304的回包現象。
然後一旦資源發生更新時,我們可以改變資源後面的識別符號,實現靜態資源非覆蓋式更新。

總結

本篇大致分析了瀏覽器快取部分的分類情況,以及細化分析。主要可分為:

  1. 強制快取

    • Expires欄位

    • Cache-Control欄位

  2. 對比快取

    • Last-Modefied欄位

    • Etag標識

  3. 瀏覽器行為引起的快取變化

  4. 移動端的快取策略

其實,在講述移動端的快取策略時,並沒有分析的特別詳細,只是大致的講解了一下目前大家都在使用的快取策略。可能之後,還會寫一篇移動端快取的細分文章。

最後,如果你對我寫的有疑問,可以與我討論。如果我寫的有錯誤,歡迎指正。你喜歡我的部落格,請給我關注Star~呦。大家一起總結一起進步。歡迎關注我的github部落格

相關文章