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緩存都有一個狀態, 標示着緩存的情況. 一份緩存清單隻有一個緩存狀態, 即使它被多個頁面引用. 以下是各個緩存狀態:
- UNCACHED(未緩存): 表明應用緩存對象還沒有初始化完成.
- IDLE(空閒): 應用緩存並未處於更新狀態.
- CHECKING(檢查): 正在檢查是否存在更新.
- DOWNLOADING(下載): 清單更新後, 重新下載全部資源到臨時緩存中.
- UPDATEREADY(更新就緒): 新版本的緩存下載完成, 全部就緒, 隨即觸發事件 updateready.
- OBSOLETE(廢棄): 應用緩存已被廢棄.
- applicationCache
//webview下
var cache = window.applicationCache;
//shared worker中
var cache = self.applicationCache;
以下是屬性和方法:
-
status: 返回當前頁面的應用緩存的狀態, 通常開啓應用緩存的頁面可能返回1, 其他頁面則返回0.
-
update(): 手動觸發應用緩存的更新.
注意:
(1) 若有更新, 則依次觸發①檢查事件(Checking event), ②下載事件(Downloading event), ③下載進度事件(Progress event), ④更新完成事件(UpdateReady event);
(2) 若無更新, 則依次觸發①檢查事件(Checking event), ②無更新事件(NoUpdate event);
(3) 在未開啓應用緩存的頁面調用將拋出Uncaught DOMException 錯誤.
update() 方法通常在長時間不關閉的頁面使用, 比如說郵箱應用, 用於定期檢測可能的更新.
- abort(): 取消應用緩存的更新. 可用於節省有限的網絡帶寬.
- 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:
- 找到Ngnix服務器配置文件mime.types
- 編輯mime.types
- 添加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緩存規則
- 遵循全量緩存的規律. 即: manifest文件改動後, 將重新緩存一遍所有的文件(包括html本身和動態添加的需要緩存的文件,即使緩存列表中沒有該html). 第一次緩存過程中如果出現緩存失敗的文件, 那麼, 第二訪問, 又將重新緩存一遍所有的文件. 以此類推.
- manifest文件本身不能寫進緩存清單, 否則連同html和資源在其緩存失效之前, 將永遠不能獲得更新.
- 即使manifest文件丟失, 緩存依然有效. 不過從此以後, 引入該manifest的html, 將永遠不能獲得更新.
- webview的緩存現象
通常, webview的緩存有如下三種現象:
- 普通網頁(無manifest文件), 不受manifest緩存影響, 緩存只走 http cache.
- 包含manifest文件的網頁, 緩存文件只受manifest緩存影響(只有manifest文件改變時纔會更新緩存資源), 緩存資源完全與 http cache 無關, 但是 NETWORK 段落後需要訪問網絡的文件, 將繼續走 http cache.
- webview直接加載manifest緩存過的文件時, 優先加載第一個manifest緩存的該文件, 如果沒有找到manifest緩存, 那麼它將自動尋找 http cache 或者 在線加載.
- 最佳實踐
- 通常只使用一個manifest文件, 並保證緩存的文件儘可能的少, 以減小manifest每次更新清單中文件所耗費的時間和流量.
- 如果一定要使用兩個及以上manifest文件, 緩存文件請儘量不要相同.
- 如果以上兩條都不能保證, 那麼, 請保證儘可能在manifest緩存的狀態更新時, 主動去刷新網頁.(此時並不能保證不同網頁之間同一個緩存文件版本一致)
- 具體落地步驟
- 如果緩存的文件需要加參數運行, 建議將參數內容加到hash中, 如:cached-page.html#parameterName=value
- manifest 的引入可以使用絕對路徑或者相對路徑, 如果你使用的是絕對路徑, 那麼你的manifest文件必須和你的站點處於同一個域名下.
- manifest文件你可以保存爲任意的擴展名, 但是響應頭中以下字段須取以下定值, 以保證manifest文件正確被解析, 並且它沒有http緩存
Content-Type: text/cache-manifest
Cache-Control: max-age=0
Expires: [CURRENT TIME]
- 總結
- 離線緩存與傳統瀏覽器緩存區別:
瀏覽器緩存(Browser Caching)是爲了節約網絡的資源加速瀏覽,瀏覽器在用戶磁盤上對最近請求過的文檔進行存儲,當訪問者再次請求這個頁面時,瀏覽器就可以從本地磁盤顯示文檔,這樣就可以加速頁面的閱覽
區別:
-
離線緩存是針對整個應用,瀏覽器緩存是單個文件
-
離線緩存斷網了還是可以打開頁面,瀏覽器緩存不行
-
離線緩存可以主動通知瀏覽器更新資源
本地存儲和離線存儲有什麼不同
-
本地存儲與離線緩存都是爲了方便網頁的加載,提高用戶體驗等。
-
本地存儲一般存儲的都是數據,而離線緩存一般存儲的是網頁等。
- 試用場景
- 單地址的頁面
- 對實時性要求不高的業務
- 離線的webapp
- 優點
- 完全離線
- 資源被緩存,加載更快
- 降低server負載
- 缺點
- 含有manifest屬性的當前請求頁無論如何都會被緩存;
- 更新需要建立在manifest文件的更新,文件更新後是需要頁面再次刷新的(需要2次刷新才能獲取資源);
- 更新是全局性的,無法單獨更次年某個文件,即一個文件被更新,需要拉取全部文件來更新;
- 對於鏈接的參數變化是敏感的,任何一個參數的修改都會被(master)重新緩存(重複緩存含參頁面)index.html和Index.html?renew=1會被認爲是不同文件,分別緩存