前言
在前端開發中,快取有利於加快網頁的載入速度,同時快取能夠被反覆利用,所以可以減少流量和頻寬的開銷。
快取的分類有很多種,CDN快取、資料庫快取、代理伺服器快取和瀏覽器快取。本篇將來講解一下Web開發中的瀏覽器快取。這個在實際開發環境中往往也會被問到,或者使用到。如何去準確認清楚快取的概念,是前端必須要去學習的。如果你喜歡我的文章,歡迎評論,歡迎Star~。歡迎關注我的github部落格
正文
瀏覽器的快取問題,主要指的是http的快取——即協議層。而h5新增的storage和資料庫快取,那是應用層快取,並不被計入本篇的分析內容裡面。下面我們正式開始來進行快取的分析。
協議層的快取,其實,可以被分成強制快取和對比快取。
強制快取
首先,我們先來看一張強制快取時的時序圖,來了解一下強制快取在不同情況下的請求模式:
從圖中,我們不難看出,只有當快取失效時,才會去伺服器獲取最新資源的方式,就是強制快取。而在協議層的欄位中,可以造成強制快取的欄位有兩個Expires和Cache-Control。
1.0的時候見到我——Expires
最早使用的是Expires欄位,該欄位表示快取到期時間,即有效時間+當時伺服器的時間,然後將這個時間設定在header中返回給伺服器。因此,該時間是一個絕對時間,舉例說明:
Expires: Thu, 10 Nov 2017 08:45:11 GMT複製程式碼
圖片示例:
在響應訊息頭中,設定這個欄位之後,就可以告訴瀏覽器,在未過期之前不需要再次請求。
但是,這個欄位設定時有缺點:
由於是絕對時間,使用者可能會將客戶端本地的時間進行修改,而導致瀏覽器判斷快取失效,重新請求該資源,同時,還導致客戶端與服務端的時間不一致,致使快取失效。
1.1的時候我來了——Cache-Control
已知Expires的缺點之後,在HTTP/1.1中,增加了一個欄位Cache-Control,該欄位表示資源快取的最大有效時間,在該時間內,客戶端不需要向伺服器傳送請求
這兩者的區別就是前者是絕對時間,而後者是相對時間。我們不妨舉個例子來說明一下:
Cache-Control: max-age=2592000複製程式碼
圖片示例:
下面列舉一下Cache-Control的欄位可以帶的值:
max-age:即最大有效時間,在上面的例子中我們可以看到
no-cache:表示沒有快取,即告訴瀏覽器該資源並沒有設定快取
s-maxage:同max-age,但是僅用於共享快取,如CDN快取
public:多使用者共享快取,預設設定
private:不能夠多使用者共享,HTTP認證之後,欄位會自動轉換成private。
總結一下,自從http1.1開始,Expires逐漸被Cache-Control取代。Cache-Control是一個相對時間,即使客戶端時間發生改變,相對時間也不會隨之改變,這樣可以保持伺服器和客戶端的時間一致性。而且Cache-Control的可配置性比較強大。
對比快取
扯完強制快取,我們來看看對比快取。在解釋這個之前,是否可以先猜想一下,強制快取是,快取在未過有效期時,不需要請求資源。那麼,對比快取的原理又該如何呢?
廢話不多說,我們也先從對比快取的時序圖講起,如圖:
對比快取的過程是,先從快取中獲取對應的資料標識,然後向伺服器傳送請求,確認資料是否更新,如果更新,則返回新資料和新快取;反之,則返回304狀態碼,告知客戶端快取未更新,可繼續使用。
這正好彌補了一些強制快取的缺陷。對比快取主要應用於一些時常需要動態更新的資原始檔。
對比快取在協議裡的欄位是Last-Modified和If-Modified-Since。
別人的好夥伴——Last-Modified
Last-Modified:伺服器告知客戶端,資源最後一次被修改的時間,例如
Last-Modified: Thu, 10 Nov 2015 08:45:11 GMT複製程式碼
If-Modified-Since:再次請求時,請求頭中帶有該欄位,伺服器會將If-Modified-Since的值與Last-Modified欄位進行對比,如果相等,則表示未修改,響應304;反之,則表示修改了,響應200狀態碼,返回資料。
這個欄位可以和Cache-Control配合使用。
但是他還是有一定缺陷的:
如果資源更新的速度是秒以下單位,那麼該快取是不能被使用的,因為它的時間單位最低是秒。
如果檔案是通過伺服器動態生成的,那麼該方法的更新時間永遠是生成的時間,儘管檔案可能沒有變化,所以起不到快取的作用。
我來完善它——Etag
由於Last-modified還是存在缺陷的,儘管大多數情況下,會使用它,但當遇到我們上面所說的場景時,我們可能就需要了解一下,我們另一個小夥伴了——Etag。
Etag儲存的是檔案的特殊標識(一般都是hash生成的),伺服器儲存著檔案的Etag欄位,可以在與每次客戶端傳送If-no-match的欄位進行比較,如果相等,則表示未修改,響應304;反之,則表示已修改,響應200狀態碼,返回資料。
最後,通過一張原理圖,我們來加深一下記憶:
至此為止,兩種快取型別的快取方式已經闡述完成了,不知你是否已經心中已經有個大致的印象,當別人問起時,你可以對答如流。希望我們一同進步吧,fighting。
瀏覽器行為引起的不同
最後,我們來聊聊瀏覽器行為會引起快取的變化吧。
下面說一下瀏覽器的行為會產生怎樣的請求:
- 重新整理網頁 => 如果快取沒有失效,瀏覽器會直接使用快取;反之,則向伺服器請求資料
- 手動重新整理(F5) => 瀏覽器會認為快取失效,在請求伺服器時加上Cache-Control: max-age=0欄位,然後詢問伺服器資料是否更新。
- 強制重新整理(Ctrl + F5) => 瀏覽器會直接忽略快取,在請求伺服器時加上Cache-Control: no-cache欄位,然後重新向伺服器拉取檔案。
移動端的快取處理
在PC端或許這樣子的快取機制就已經足夠了,因為PC端不需要為網路的問題擔心。
但是,移動端卻不行,任何一個網路請求的增加,對於移動端的載入消耗時間都是比較大的(誰叫移動端的網太差呢,3G、2G)。那麼,上述的快取有什麼問題呢?其實,強制快取是沒有太大問題的,因為只要快取不到期,是不會想伺服器傳送請求的;但是如果是對比快取的情況下,304的問題就比較巨大,因為它會造成無用的請求。每次在使用快取前,都會向伺服器傳送請求確認,導致網路的延時。
一次完美的快取必須保證兩點:
- 資料快取之後,儘量減少伺服器的請求
- 如果資源更新的話,必須使得客戶端的資源一起更新。
所以,一般我們會運用的方式是:
在資原始檔後面加上表示,如config.f1ec3.js、config.v1.js之類的,然後給資源設定較長的快取時間,如一年
Cache-Control: max-age=31536000複製程式碼
這樣子,就不會造成304的回包現象。
然後一旦資源發生更新時,我們可以改變資源後面的識別符號,實現靜態資源非覆蓋式更新。
總結
本篇大致分析了瀏覽器快取部分的分類情況,以及細化分析。主要可分為:
強制快取
Expires欄位
Cache-Control欄位
對比快取
Last-Modefied欄位
Etag標識
瀏覽器行為引起的快取變化
移動端的快取策略
其實,在講述移動端的快取策略時,並沒有分析的特別詳細,只是大致的講解了一下目前大家都在使用的快取策略。可能之後,還會寫一篇移動端快取的細分文章。
最後,如果你對我寫的有疑問,可以與我討論。如果我寫的有錯誤,歡迎指正。你喜歡我的部落格,請給我關注Star~呦。大家一起總結一起進步。歡迎關注我的github部落格