h5離線緩存

1. 協議緩存

舉個例子:
更新了一張圖片,發佈之後反覆重新進頁面總是看不到更新

說明是協議緩存?

http協議緩存機制是指通過HTTP協議頭裏的Cache-Control(或 Expires)和Last-Modified(或Etag)等字段來控制文件緩存的機制。

  • Cache-Control 用於控制文件在本地緩存有效時長。最常見的,比如服務器回包:Cache-Control:max-age=600 表示文件在本地應該緩存,且有效時長是600秒(從發出請求算起)。在接下來600秒內,如果有請求這個資源,瀏覽器不會發出 HTTP 請求,而是直接使用本地緩存的文件。
  • Last-Modified 是標識文件在服務器上的最新更新時間。下次請求時,如果文件緩存過期,瀏覽器通過 If-Modified-Since 字段帶上這個時間,發送給服務器,由服務器比較時間戳來判斷文件是否有修改。如果沒有修改,服務器返回304告訴瀏覽器繼續使用緩存;如果有修改,則返回200,同時返回最新的文件。

Cache-Control 還有一個同功能的字段:Expires。Expires 的值一個絕對的時間點,如:Expires: Thu, 10 Nov 2015 08:45:11 GMT,表示在這個時間點之前,緩存都是有效的。

Expires 是 HTTP1.0 標準中的字段,Cache-Control 是 HTTP1.1 標準中新加的字段,功能一樣,都是控制緩存的有效時間。當這兩個字段同時出現時,Cache-Control 是高優化級的。

Etag 也是和 Last-Modified一樣,對文件進行標識的字段。不同的是,Etag的取值是一個對文件進行標識的特徵字串。在向服務器查詢文件是否有更新時,瀏覽器通過If-None-Match 字段把特徵字串發送給服務器,由服務器和文件最新特徵字串進行匹配,來判斷文件是否有更新。沒有更新回包304,有更新回包200。Etag和Last-Modified可根據需求使用一個或兩個同時使用。兩個同時使用時,只要滿足其中一個條件,就認爲文件沒有更新

不過有兩種情況比較特殊:

  • 手動刷新頁面(F5):
    瀏覽器會直接認爲緩存已經過期(可能緩存還沒有過期),在請求中加上字段:Cache-Control:max-age=0,發包向服務器查詢是否有文件是否有更新。
  • 強制刷新頁面(Ctrl+F5):
    瀏覽器會直接忽略本地的緩存(有緩存也會認爲本地沒有緩存),在請求中加上字段:Cache-Control:no-cache(或Pragma:no-cache),發包向服務重新拉取文件。

2. 應用緩存(離線緩存)

除了http協議緩存,HTML5 提供一種應用程序緩存機制,使得基於web的應用程序可以離線運行。爲了能夠讓用戶在離線狀態下繼續訪問 Web 應用,開發者需要提供一個 cache manifest 文件。這個文件中列出了所有需要在離線狀態下使用的資源,瀏覽器會把這些資源緩存到本地。
雖然manifest的技術已被web標準廢棄, 但這不影響我們嘗試去了解它. 也正是因爲manifest的應用緩存機制如此誘人, 餓了麼 和 office 365郵箱等都還在使用着它!

使用方法:

<!-- index.html -->
<!DOCTYPE HTML>
<html manifest="test.manifest">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="/appactivity/testmain/css/index.css">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    我是哈哈哈哈哈
</body>
</html>

注意事項:

  • 如何開啓緩存:
<html manifest="test.manifest">
  ...
</html>

在html標籤中指定manifest文件, 便表示該網頁使用manifest進行離線緩存. 該網頁內需要緩存的文件列表需要在 test.manifest 文本文件中指定.

  • manifest緩存清單

就像寫作文一樣, manifest採用經典的三段式. 分別爲: CACHE, NETWORK 和 FALLBACK. 如下, 先看一個栗子?:

#test.manifest文件
CACHE MANIFEST
# Time: Sat Jun 04 2016 17:11:50 GMT+0800 (CST)
# webpack-multipage v1.0.0==== ========

CACHE:
css/index.css

NETWORK:
js/app.js

FALLBACK:
/other 404.html

第一行必須以 CACHE MANIFEST 開頭, 後可跟若干字符註釋, 註釋從#號開始. 跟在 CACHE MANIFEST 行後的文件。

第一段內容以 CACHE: 開頭

每行列出一個, 這些文件是需要緩存的文件. 因此 index.css 會被緩存, 不需要訪問網絡.

第二段內容以 NETWORK: 開始

跟在該行後的文件表示需要訪問網絡. 如: app.js 將直接從網絡上下載, 並不走manifest cache, 如果除了第一段中緩存的文件以外, 其他文件都從網絡上獲取, 那麼此時可將 app.js 改爲 * (通配符).

第三段內容以 FALLBACK: 開始

跟在該行後的文件表示會有一個替代方案. 如: 當訪問 /other 路徑時, 如果訪問失敗, 那麼將自動加載 404.html 作爲替代.

  • manifest緩存狀態

每個manifest緩存都有一個狀態, 標示着緩存的情況. 一份緩存清單隻有一個緩存狀態, 即使它被多個頁面引用. 以下是各個緩存狀態:

  1. UNCACHED(未緩存): 表明應用緩存對象還沒有初始化完成.
  2. IDLE(空閒): 應用緩存並未處於更新狀態.
  3. CHECKING(檢查): 正在檢查是否存在更新.
  4. DOWNLOADING(下載): 清單更新後, 重新下載全部資源到臨時緩存中.
  5. UPDATEREADY(更新就緒): 新版本的緩存下載完成, 全部就緒, 隨即觸發事件 updateready.
  6. OBSOLETE(廢棄): 應用緩存已被廢棄.
  • applicationCache
//webview下
var cache = window.applicationCache;
//shared worker中
var cache = self.applicationCache;

以下是屬性和方法:

  1. status: 返回當前頁面的應用緩存的狀態, 通常開啓應用緩存的頁面可能返回1, 其他頁面則返回0.

  2. update(): 手動觸發應用緩存的更新.

注意:

(1) 若有更新, 則依次觸發①檢查事件(Checking event), ②下載事件(Downloading event), ③下載進度事件(Progress event), ④更新完成事件(UpdateReady event);

(2) 若無更新, 則依次觸發①檢查事件(Checking event), ②無更新事件(NoUpdate event);

(3) 在未開啓應用緩存的頁面調用將拋出Uncaught DOMException 錯誤.

update() 方法通常在長時間不關閉的頁面使用, 比如說郵箱應用, 用於定期檢測可能的更新.

  1. abort(): 取消應用緩存的更新. 可用於節省有限的網絡帶寬.
  2. swapCache(): 如果存在一個更新版本的應用緩存, 那麼它將切換過去, 否則將拋出 Uncaught DOMException 錯誤. 通常, 我們會在updateready事件觸發之後手動調用swapCache()方法, swapCache的切換隻對後續加載的緩存文件有效, 已經加載成功的資源並不會重新加載.

那麼如何利用好上述api更新一個頁面的應用緩存呢? 別急, Beginner’s Guide to Using the Application Cache 一文中提供瞭如下的樣板方法:

// Check if a new cache is available on page load.
window.addEventListener('load', function(e) {
  window.applicationCache.addEventListener('updateready', function(e) {
    if (window.applicationCache.status == window.applicationCache.UPDATEREADY) {
      // Browser downloaded a new app cache.
      // Swap it in and reload the page to get the new hotness.
      window.applicationCache.swapCache();
      if (confirm('A new version of this site is available. Load it?')) {
        window.location.reload();
      }
    } else {
      // Manifest didn't changed. Nothing new to server.
    }
  }, false);
}, false);
  • 服務器配置方法

    nginx:

    1. 找到Ngnix服務器配置文件mime.types
    2. 編輯mime.types
    3. 添加manifest文件映射
types {  
      text/html                             html htm shtml;  
      text/css                              css;  
      text/xml                              xml rss;  
      image/gif                             gif;  
      image/jpeg                            jpeg jpg;  
      application/x-javascript              js;  
      application/atom+xml                  atom;  
    
      text/mathml                           mml;  
      text/plain                            txt;  
      text/vnd.sun.j2me.app-descriptor      jad;  
      text/vnd.wap.wml                      wml;  
     text/x-component                      htc;  
   
      image/png                             png;  
     image/tiff                            tif tiff;  
      image/vnd.wap.wbmp                    wbmp;  
      image/x-icon                          ico;  
      image/x-jng                           jng;  
     image/x-ms-bmp                        bmp;  
      image/svg+xml                         svg;  
    
      application/java-archive              jar war ear;  
      application/mac-binhex40              hqx;  
      application/msword                    doc;  
     application/pdf                       pdf;  
      application/postscript                ps eps ai;  
      application/rtf                       rtf;  
      application/vnd.ms-excel              xls;  
      application/vnd.ms-powerpoint         ppt;  
     application/vnd.wap.wmlc              wmlc;  
      application/vnd.wap.xhtml+xml         xhtml;  
      application/x-cocoa                   cco;  
      application/x-java-archive-diff       jardiff;  
      application/x-java-jnlp-file          jnlp;  
      application/x-makeself                run;  
      application/x-perl                    pl pm;  
      application/x-pilot                   prc pdb;  
      application/x-rar-compressed          rar;  
      application/x-RedHat-package-manager  rpm;  
      application/x-sea                     sea;  
      application/x-shockwave-flash         swf;  
      application/x-stuffit                 sit;  
      application/x-tcl                     tcl tk;  
      application/x-x509-ca-cert            der pem crt;  
      application/x-xpinstall               xpi;  
      application/zip                       zip;  
    
      application/octet-stream              bin exe dll;  
      application/octet-stream              deb;  
      application/octet-stream              dmg;  
      application/octet-stream              eot;  
      application/octet-stream              iso img;  
      application/octet-stream              msi msp msm;  
    
      audio/midi                            mid midi kar;  
      audio/mpeg                            mp3;  
     audio/x-realaudio                     ra;  
   
      video/3gpp                            3gpp 3gp;  
     video/mpeg                            mpeg mpg;  
      video/quicktime                       mov;  
     video/x-flv                           flv;  
      video/x-mng                           mng;  
      video/x-ms-asf                        asx asf;  
      video/x-ms-wmv                        wmv;  
     video/x-msvideo                       avi;  
      application/x-nokia-widget            wgz;  
    
      text/cache-manifest                   mf manifest;  
  }  

4. 重啓nginx

注意: manifest後面一定要加

  • manifest緩存規則
  1. 遵循全量緩存的規律. 即: manifest文件改動後, 將重新緩存一遍所有的文件(包括html本身和動態添加的需要緩存的文件,即使緩存列表中沒有該html). 第一次緩存過程中如果出現緩存失敗的文件, 那麼, 第二訪問, 又將重新緩存一遍所有的文件. 以此類推.
  2. manifest文件本身不能寫進緩存清單, 否則連同html和資源在其緩存失效之前, 將永遠不能獲得更新.
  3. 即使manifest文件丟失, 緩存依然有效. 不過從此以後, 引入該manifest的html, 將永遠不能獲得更新.
  • webview的緩存現象

通常, webview的緩存有如下三種現象:

  1. 普通網頁(無manifest文件), 不受manifest緩存影響, 緩存只走 http cache.
  2. 包含manifest文件的網頁, 緩存文件只受manifest緩存影響(只有manifest文件改變時纔會更新緩存資源), 緩存資源完全與 http cache 無關, 但是 NETWORK 段落後需要訪問網絡的文件, 將繼續走 http cache.
  3. webview直接加載manifest緩存過的文件時, 優先加載第一個manifest緩存的該文件, 如果沒有找到manifest緩存, 那麼它將自動尋找 http cache 或者 在線加載.
  • 最佳實踐
  1. 通常只使用一個manifest文件, 並保證緩存的文件儘可能的少, 以減小manifest每次更新清單中文件所耗費的時間和流量.
  2. 如果一定要使用兩個及以上manifest文件, 緩存文件請儘量不要相同.
  3. 如果以上兩條都不能保證, 那麼, 請保證儘可能在manifest緩存的狀態更新時, 主動去刷新網頁.(此時並不能保證不同網頁之間同一個緩存文件版本一致)
  • 具體落地步驟
  1. 如果緩存的文件需要加參數運行, 建議將參數內容加到hash中, 如:cached-page.html#parameterName=value
  2. manifest 的引入可以使用絕對路徑或者相對路徑, 如果你使用的是絕對路徑, 那麼你的manifest文件必須和你的站點處於同一個域名下.
  3. manifest文件你可以保存爲任意的擴展名, 但是響應頭中以下字段須取以下定值, 以保證manifest文件正確被解析, 並且它沒有http緩存
Content-Type: text/cache-manifest
Cache-Control: max-age=0
Expires: [CURRENT TIME]
  • 總結
  1. 離線緩存與傳統瀏覽器緩存區別:

瀏覽器緩存(Browser Caching)是爲了節約網絡的資源加速瀏覽,瀏覽器在用戶磁盤上對最近請求過的文檔進行存儲,當訪問者再次請求這個頁面時,瀏覽器就可以從本地磁盤顯示文檔,這樣就可以加速頁面的閱覽

區別

  • 離線緩存是針對整個應用,瀏覽器緩存是單個文件

  • 離線緩存斷網了還是可以打開頁面,瀏覽器緩存不行

  • 離線緩存可以主動通知瀏覽器更新資源

本地存儲和離線存儲有什麼不同

  • 本地存儲與離線緩存都是爲了方便網頁的加載,提高用戶體驗等。

  • 本地存儲一般存儲的都是數據,而離線緩存一般存儲的是網頁等。

  1. 試用場景
  • 單地址的頁面
  • 對實時性要求不高的業務
  • 離線的webapp
  1. 優點
  • 完全離線
  • 資源被緩存,加載更快
  • 降低server負載
  1. 缺點
  • 含有manifest屬性的當前請求頁無論如何都會被緩存;
  • 更新需要建立在manifest文件的更新,文件更新後是需要頁面再次刷新的(需要2次刷新才能獲取資源);
  • 更新是全局性的,無法單獨更次年某個文件,即一個文件被更新,需要拉取全部文件來更新;
  • 對於鏈接的參數變化是敏感的,任何一個參數的修改都會被(master)重新緩存(重複緩存含參頁面)index.html和Index.html?renew=1會被認爲是不同文件,分別緩存
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章