HTTP快取和瀏覽器的本地儲存

擱淺發表於2019-08-16

一、HTTP快取

http請求做為影響前端效能極為重要的一環,因為請求受網路影響很大,如果網路很慢的情況下,頁面很可能會空白很久。對於首次進入網站的使用者可能要通過優化介面效能和介面數量來解決。但是,對於重複進入頁面的使用者,除了瀏覽器快取,http快取可以很大程度對已經載入過的頁面進行優化。

1.快取位置

clipboard.png

從快取位置上來看,分為4種,從上往下依次檢查是否命中,如果但都沒有命中則重新發起請求。
Service Worker 是執行在瀏覽器背後的獨立執行緒,一般可以用來實現快取功能。使用 Service Worker的話,傳輸協議必須為 HTTPS。
Memory Cache 也就是記憶體中的快取,主要包含的是當前中頁面中已經抓取到的資源,例如頁面上已經下載的樣式、指令碼、圖片等。讀取記憶體中的資料肯定比磁碟快,記憶體快取雖然讀取高效,可是快取持續性很短,會隨著程式的釋放而釋放。 一旦我們關閉 Tab 頁面,記憶體中的快取也就被釋放了。
記憶體快取中有一塊重要的快取資源是preloader相關指令(例如<link rel="prefetch">)下載的資源。它可以一邊解析js/css檔案,一邊網路請求下一個資源。
Disk Cache 也就是儲存在硬碟中的快取,讀取速度慢點,但是什麼都能儲存到磁碟中,比之 Memory Cache 勝在容量和儲存時效性上。
絕大部分的快取都來自Disk Cache,在HTTP 的協議頭中設定。
Push Cache(推送快取)是 HTTP/2 中的內容,當以上三種快取都沒有命中時,它才會被使用。它只在會話(Session)中存在,一旦會話結束就被釋放,並且快取時間也很短暫,在Chrome瀏覽器中只有5分鐘左右,同時它也並非嚴格執行HTTP頭中的快取指令。

2.使用者操作對快取的影響

clipboard.png

clipboard.png

下面主要說一下前端優化能入手的地方,也就是強快取協商快取,並且快取策略都是通過設定 HTTP Header 來實現的。

clipboard.png

3.強快取

瀏覽器在第一次訪問介面後的response headers裡會攜帶一些欄位,這些欄位決定關於這個請求的快取情況,
與強快取相關的header欄位有兩個:

1、expires:過氣網紅,這是http1.0時的規範;它的值為一個絕對時間的GMT格式的時間字串,如Mon, 10 Jun 2015 21:31:12 GMT,如果傳送請求的時間在expires之前,那麼本地快取始終有效,否則就會傳送請求到伺服器來獲取資源

2、cache-control:新星:max-age=number,這是http1.1時出現的header資訊,主要是利用該欄位的max-age值來進行判斷,它是一個相對值;資源第一次的請求時間和Cache-Control設定的有效期,計算出一個資源過期時間,再拿這個過期時間跟當前的請求時間比較,如果請求時間在過期時間之前,就能命中快取,否則就不行;
no-cache:不使用本地快取。需要使用協商快取,先與伺服器確認返回的響應是否被更改,如果之前的響應中存在ETag,那麼請求的時候會與服務端驗證,如果資源未被更改,則可以避免重新下載。

no-store:直接禁止遊覽器快取資料,每次使用者請求該資源,都會向伺服器傳送一個請求,每次都會下載完整的資源。

public:可以被所有的使用者快取,包括終端使用者和CDN等中間代理伺服器。

private:只能被終端使用者的瀏覽器快取,不允許CDN等中繼快取伺服器對其快取。
  注意:如果cache-control與expires同時存在的話,cache-control的優先順序高於expires

強快取時段命中,會直接從快取中返回資料,返回值200;這一時間段,不管介面內容有沒有變化都不會進行請求更新。

4.協商快取

當沒有強快取時,會向服務端尋求幫助,也就是問一下服務端有沒有更改,向介面判斷是否有快取。如果命中協商快取則返回304狀態碼,並且從本地返回快取內容。如果沒有命中,則重新發起請求。
協商快取需要跟服務端通過特殊標示連線,即第一次請求的響應頭帶上某個欄位(Last-Modified或者Etag),則後續請求則會帶上對應的請求欄位(If-Modified-Since或者If-None-Match),若響應頭沒有Last-Modified或者Etag欄位,則請求頭也不會有對應的欄位。

具體過程如下:

Last-Modified/If-Modified-Since

1.瀏覽器第一次跟伺服器請求一個資源,respone的header里加上Last-Modified:表示這個資源在伺服器上的最後修改時間

2.瀏覽器再次跟伺服器請求這個資源時,在request的header上加上If-Modified-Since的header:上一次請求時返回的Last-Modified的值

3.伺服器再次收到資源請求時,會判斷最後修改時間是否有變化,如果沒有變化則返回304 Not Modified,但是不會返回資源內容;如果有變化,就正常返回資源內容,Last-Modified會被修改為最新的值。如果沒有變化,伺服器返回304 Not Modified,Last-Modified不會修改,response header中不會再新增Last-Modified的header

4.瀏覽器收到304的響應後,就會從快取中載入資源

Etag/If-None-Match

由伺服器生成的每個資源的唯一標識字串,只要資源有變化就這個值就會改變;其判斷過程與Last-Modified/If-Modified-Since類似,與Last-Modified不一樣的是,當伺服器返回304 Not Modified的響應時,由於ETag重新生成過,response header中還會把這個ETag返回,即使這個ETag跟之前的沒有變化。

1.一些檔案也許會週期性的更改,但是他的內容並不改變(僅僅改變的修改時間),這個時候我們並不希望客戶端認為這個檔案被修改了,而重新GET;

2.某些檔案修改非常頻繁,比如在秒以下的時間內進行修改,(比方說1s內修改了N次),If-Modified-Since能檢查到的粒度是s級的,這種修改無法判斷(或者說UNIX記錄MTIME只能精確到秒);

3.某些伺服器不能精確的得到檔案的最後修改時間。

Last-Modified與ETag是可以一起使用的,伺服器會優先驗證ETag,一致的情況下,才會繼續比對Last-Modified,最後才決定是否返回304。

二、瀏覽器本地儲存

瀏覽器本地快取最常用的是cookie、localStroage、sessionStroage、webSql、indexDB。

1.cookie使用

cookie的用法很簡單,可以通過服務端設定,js也可以通過documnet.cookie="名稱=值;"(不要忘記以;分割)來設定。
cookie的字串可以用encodeURIComponent()來保證它不包含任何逗號、分號或空格(cookie值中禁止使用這些值).
cookie一般用做為登陸態儲存、密碼、個人資訊等關鍵資訊儲存使用,所以為了安全也是遵守同源策略原則的。
可以通過下面引數具體設定:
;path=path (例如 '/', '/mydir') 如果沒有定義,預設為當前文件位置的路徑。
;domain=domain (例如 'example.com', 'subdomain.example.com') 如果沒有定義,預設為當前文件位置的路徑的域名部分。與早期規範相反的是,在域名前面加 . 符將會被忽視,因為瀏覽器也許會拒絕設定這樣的cookie。如果指定了一個域,那麼子域也包含在內。
;max-age=max-age-in-seconds (例如一年為606024*365)
;expires=date-in-GMTString-format 如果沒有定義,cookie會在對話結束時過期這個值的格式參見Date.toUTCString()
;secure (cookie只通過https協議傳輸)
;HttpOnly 限制web頁面程式的browser端script程式讀取cookie

缺點
容量有限制,不能超過4kb
在請求頭上帶著資料安全性差

2.localStorage和sessionStorage使用

html5新增本地儲存,localStorage生命週期是永久,除非主動清除localStorage資訊,否則這些資訊將永遠存在。存放資料大小為一般為5MB,sessionStorage僅在當前會話下有效,關閉頁面或瀏覽器後被清除。而且它僅在客戶端(即瀏覽器)中儲存,不參與和伺服器的通訊。也是遵守同源策略原則

// 1、儲存資料到本地
// 第一個引數是儲存的變數名,第二個是賦給變數的值
localStorage.setItem('key', 'value');
//複雜型別儲存需要**利用JSON.stringify**將物件轉換成字串;
//利用**JSON.parse**將字串轉換成物件
// 2、從本地儲存獲取資料
localStorage.getItem('key');
// 3、從本地儲存刪除某個已儲存的資料
localStorage.removeItem('key');
// 4、清除所有儲存的資料
localStorage.clear();

3. Web SQL

WebSQL是前端的一個獨立模組,是web儲存方式的一種,我們除錯的時候會經常看到,只是一般很少使用。並且,當前只有谷歌支援,ie和火狐均不支援。
主要方法:

1.openDatabase:這個方法使用現有的資料庫或者新建的資料庫建立一個資料庫物件。
2.transaction:這個方法讓我們能夠控制一個事務,以及基於這種情況執行提交或者回滾。
3.executeSql:這個方法用於執行實際的 SQL 查詢。

4.indexDB

IndexedDB 就是瀏覽器提供的本地資料庫,它可以被網頁尾本建立和操作。IndexedDB 允許儲存大量資料,提供查詢介面,還能建立索引。這些都是 LocalStorage 所不具備的。就資料庫型別而言,IndexedDB 不屬於關係型資料庫(不支援 SQL 查詢語句),更接近 NoSQL 資料庫。
具體概念參考:參考文章

相關文章