談談關於前端的快取的問題

Gentle_Fung發表於2017-11-10

        我們都知道對頁面進行快取能夠有利於減少請求傳送,從而達到對頁面的優化。不過在我前端工作的生涯中一直以為前端就是寫寫頁面,寫寫互動,就已經很了不起,這種沒有志向的想法發導致我日後的工作一直處於瓶頸。做人嘛總要有夢想嘛,不然跟一條鹹魚有什麼區別。最近我一直在關於前端優化的問題,原來對頁面進行有效快取對於響應速度會大大提高。我也是綜合自己看到的幾篇文章,談談看法,權當是一次學習筆記吧,有什麼不對的請多多包涵。廢話不多說,開始正題。

快取機制

快取分為服務端側(server side,比如 Nginx、Apache)和客戶端側(client side,比如 web browser)。

服務端緩存又分為 代理伺服器快取 和 反向代理伺服器快取(也叫閘道器快取,比如 Nginx反向代理、Squid等),其實廣泛使用的 CDN 也是一種服務端快取,目的都是讓使用者的請求走”捷徑“,並且都是快取圖片、檔案等靜態資源。

瀏覽器快取控制機制有兩種:HTML Meta標籤 vs. HTTP頭資訊

<META HTTP-EQUIV="Pragma" CONTENT="no-cache">

上述程式碼的作用是告訴瀏覽器當前頁面不被快取,每次訪問都需要去伺服器拉取。使用上很簡單,但只有部分瀏覽器可以支援,而且所有快取代理伺服器都不支援,因為代理不解析HTML內容本身。

談談關於前端的快取的問題

1、服務端快取相關

什麼是Etag?什麼是Last-Modified?等等這些,都是什麼鬼,以前我一看到都是直接懵逼。

首先我們要先根據http請求頭以及響應頭 先看一些跟快取相關的報文頭cache-control, if-none-match, if-modified-since, Etag,expires, last-modified,
request header快取相關:
cache-control:
其快取指令對於前段常用的有如下no-cache、no-store、max-age這幾個值;分別來說一下
no-cache:
表面意為“資料內容不被快取”,而實際資料是被快取到本地的,只是每次請求時候直接繞過快取這一環節直接向伺服器請求最新資源,由於瀏覽器解釋不一樣,
例如ie中我們設定了no-cache之後,請求雖然不會直接使用快取,但是還會用快取資料與伺服器資料進行一致性檢測(也就是說還是有機率會用到快取的),
firefox中則完全無視no-cache存在,詳細解釋見no-store;
no-store:
指示快取不儲存此次請求的響應部分。與no-cache比較來說,一個是不用快取,一個是不儲存快取;按理來說這個設定更加粗暴直接禁用快取,
但是具體實現起來 瀏覽器之間差異卻特別大,一般不會直接用該欄位進行設定,不過no-store是為了防止快取被惡意修改儲存路徑導致資訊被洩露而設定的,
畢竟有它的用處,在firefox中實現快取是通過檔案另存為將快取副本儲存到本地,直接利用no-cache對其是無效的,如果加上no-store設定的話 則可以起到與no-cache一樣的效果;
即:cache-control:no-cache,no-store;可以確保在支援http1.1版本中各大瀏覽器回車後退重新整理無快取;
再加上Pragma: no-cache設定相容版本1.0即可(不過為了防止一致性檢測時候的萬一我們還是最好加上一致性檢測的內容,如下所示幾種方式);
max-age:
例如Cache-control: max-age=3;表示此次請求成功後3秒之內傳送同樣請求不會去伺服器重新請求,而是使用本地快取;同樣我們如果設定max-age=0表示立即拋棄快取直接傳送請求到伺服器
一致性檢測分為兩種方式:1.檢測日期是否過期,檢測資源是否更新;
if-none-match:
該欄位與響應中的eTag一起使用,表示檢查實體是否有更新改變;客戶端第一次傳送請求時候響應報文會包含欄位Etag,表示資源狀態,當資源改變後該值也會改變(客戶端不必關心該值怎麼生成)
然後快取儲存下該欄位,第二次已經有該快取時候在瀏覽本地快取時候會將該值賦給if-none-match欄位傳送給伺服器,伺服器將傳送的值與當前的狀態進行對比,
如果值一樣的話則答覆304去使用快取資料,如果值改變了則傳送最新資料給客戶端替代現有快取資料,並且返回狀態200;
if-modified-since:
該欄位與last-modified配合使用,跟上述原理差不多,都是響應端先返回一個last-modified時間欄位,再次請求時候 request頭部會將快取中的last-modified欄位拿出來賦給if-modified-since,
傳送給伺服器,伺服器去判斷時間是否過期,如未過期則返回304,告訴客戶使用快取資料,如果過期則重新返回一個last-modified並且返回200;
repsonse header快取相關:
Etag:
剛才也說過 是跟if-none-match配合去使用,它根據實體內容生成的一段hash字串(類似於MD5或者SHA1之後的結果),可以標識資源的狀態。 當資源傳送改變時,ETag也隨之發生變化。
使用Etag主要是為了解決根據時間無法解決的問題:比如檔案修改頻繁(秒之內修改),導致根據時間無法判斷是否更新;以及修改時間變了,但是內容沒變(我們應該認為該檔案是沒變的)
expires:
表示快取過期時間例如:expires:Mon Dec 30 2011 11:01:19 GMT,跟cache-control中的max-age作用一樣,不過在碰見max-age之後,該值會被覆蓋從而被max-age替代;
last-modified:
表示檔案最後修改時間;
另外響應端的報文頭也有對cache-content的規定,與request大體相同,另有未提及的 歡迎大家補充

使用快取:

預設情況下,瀏覽器都會使用快取資料,

在f5重新整理情況下 瀏覽器會傳送一致性驗證去伺服器驗證是否使用快取,而瀏覽器直接回車則表示直接應用快取不需要去伺服器驗證;所以我們就按照f5重新整理去解釋實現使用快取:

一般來說前端預設是使用快取的,預設情況下伺服器端以及前端都會使用快取資料,或者是根據etag或者是根據max-age或者是根據expires根據伺服器不同去不同實現;

實際中大部分不需要我們手動去實現,而有些我們不確定是否使用快取的情況下我們可以手動加以干涉強制使用快取資料:

例如某個靜態檔案包括html或者圖片我們需要使用快取來提高處理速度,

方法一:

在伺服器進行配置其max-age或者expires使其設定一個過期值為當前一年之後。這樣每次進行檢驗時候都會使用快取中檔案.例如在.htaccess中

<IfModule mod_headers.c>

<FilesMatch ".(gif|jpg|jpeg|png|ico)$">

Header set Cache-Control "max-age=604800"

</FilesMatch>

方法二:

前端設定if-modified-since去設定一個上次修改時間大於當前日期,

方法三:

伺服器端根據etag去判斷是否匹配來根據實際業務來使用快取;

後面兩個方法屬於弱快取資料頭,需要浪費http連線,所以建議使用第一種方式;

禁用快取:

方法一:

可以在meta標籤標明<meta http-equiv="pragma" content="no-cache">

<meta http-equiv="cache-control" content="no-cache">

<meta http-equiv="expires" content="0">

方法二:

也可以動態去setRequestHeader,強制不用快取設定組合如下:

cache-control='no-cache,no-store'

pragma='no-cache'

if-modified-since=0;

方法三:

請求端設定if-modified-since為已經過期的某個時間,可以是幾年前或者幾十年前。

方法四:

服務端設定Expires為過期某個時間,例如php中header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");

實際開發中如果需要一致性檢測則儘量去配合Etag以及last-Modified去進行比較然後返回使用快取還是新資料;這個有點偏伺服器端了,不再贅述

方法五:

url後面加隨機數或者時間戳url += “&random=” + Math.random()這個方法js以及php經常用,原理就是每個請求的url都不一樣這樣一來快取中找不到對應資料,就自動去伺服器尋找最新資源;

2、瀏覽器快取相關

瀏覽器快取是瀏覽器端儲存資料用於快速讀取或避免重複資源請求的優化機制,有效的快取使用可以避免重複的網路請求和瀏覽器快速地讀取本地資料,整體上加速網頁展示給使用者。瀏覽器端快取的機制種類較多,開啟瀏覽器的除錯模式->resources左側就有瀏覽器的8種快取機制

談談關於前端的快取的問題

上述的快取機制js都有相關的api進行操作,請自行查詢。上面其實都是我貼上複製的,因為這幾篇文章讓當時的我有種醍醐灌頂的感覺。詳情可以參考如下連結

1、寫給前端的http快取詳解

2、瀏覽器端的九種快取機制介紹

3、http快取提高效能


相關文章