關於離線緩存Application Cache /使用 manifest文件緩存

Application Cache的配置文件

首先需要在服務器上建立一個文件,裏面的內容確定了哪些文件需要緩存,哪些文件不需要,如果資源無法訪問會使用什麼頁面等

這個文件一般爲.appcache類型,稱爲緩存清單(cache manifest)文件,一個完整的緩存清單文件如下:

CACHE MANIFEST
# version xx.xx.xx
CACHE:
needBeCached.png
needBeCached2.js

NETWORK:
notNeedBeCached.html
notNeedBeCached2.css

FALLBACK:
/ 404.html

可以看到,文件的頭部信息CACHE MANIFEST用來標註這個文件是緩存清單文件,其後一般情況下(最好是)跟着一行標明版本的註釋,這行註釋非常重要,將在後面文件加載部分詳細介紹這行註釋的重要性

CACHE部分

除了頭部信息,這個緩存清單文件分爲幾部分,第一部分爲CACHE部分:

CACHE:
needBeCached.png
needBeCached2.js

這一部分標註了哪些資源文件需要被緩存可以列出多個

如果有路徑,如需要緩存blog下的blog.css文件,可以寫成blog/blog.css

另外CACHE:可以被省略,讓需要緩存的資源文件直接跟在註釋之後

NETWORK部分

第二部分爲NETWORK部分:

NETWORK:
notNeedBeCached.html
notNeedBeCached2.css

這一部分定義了哪些文件不需要緩存,這些文件需要與服務器連接

與CACHE一樣,可以定義多個資源,而如果直接輸入一個文件夾路徑,也是合法的,比如/blog這樣,blog文件夾下的所有文件都不會被緩存

可以使用通配符來,如除了上面CACHE中定義的資源,其他都必須與服務器連接:

NETWORK:
*

需要注意一點是,載有這個manifest文件的HTML文檔將一定會緩存,這個會在後面再次提到

FALLBACK部分

第三部分爲FALLBACK部分:

FALLBACK:
/ 404.html

這一部分指定了一個後備頁面,當資源無法訪問時,瀏覽器會使用該頁面

同樣可以定義多條記錄,每條記錄列出兩個URI,一個表示資源,一個表示後備頁面。需要注意的是兩個資源文件都需要使用相對路徑切與manifest文件同源

同樣可以使用通配符

保存和引用manifest文件

manifest文件可以保存在服務器上,保存爲.appcache後綴,但必須與應用本身同源。在HTML文檔中,可以指定清單文件的相對路徑和絕對URL。需要注意的是,manifest文件的MIME類型必須是text/cache-manifest

需要在HTML文檔中引入manifest文件,可以使用類似如下代碼:

<!doctype html>
<html manifest="manifest.appcache">
...
</html>

這樣,HTML文檔加載後,就會根據manifest.appcache的內容來緩存資源文件,在下次訪問相同頁面的時候,會直接使用緩存的資源文件來進行加速

緩存和加載機制

在第一次訪問時,瀏覽器加載完HTML文檔後,會查看其是否有引入manifest文件。若引入,則加載manifest文件,然後根據manifest的文件內容進行資源的緩存,並緩存當前文檔

之後訪問,瀏覽器首先會查看manifest文件是否被修改(無論是內容還是註釋),如果被修改,將當做第一次訪問,重新根據manifest文件內容進行緩存

如果應用緩存存在,且manifest沒有被修改,瀏覽器直接從緩存中加載文檔(注意:加載文檔)和資源,不會訪問網絡(注意:無論聯網與否,都不會訪問網絡)

在緩存多個資源文件時,瀏覽器下載資源文件會先放在一個臨時的緩存中,如果有任何一個資源文件下載失敗,瀏覽器將停止其他緩存資源的下載,並清除臨時緩存。如果所有資源文件都被成功下載,瀏覽器將會把這些資源文件以及引用manifest文件的HTML文檔移動到永久離線緩存中

滿滿的都是坑

一些小坑

  1. 需要注意的是manifest文件放在服務器上,MIME類型必須是text/cache-manifest,如果使用 Apache,需要修改.htaccess文件。IE下默認application/octet-stream,需要在服務器指定
  2. 每個需要緩存的頁面的html都需要加入manifest屬性
  3. 不要將manifest文件本身加入緩存,如果加入,瀏覽器將不會檢測到服務器上manifest的更新,頁面版本將萬年不變
  4. 不要以爲一個資源文件加載失敗,其他文件就會被緩存,原因參見緩存和加載機制的最後一段

一些大坑

  1. 在manifest文件中定義的資源全部被成功加載後,這些資源文件連同引用manifest文件的HTML文檔一併被移動到永久離線緩存中。所以如果想只緩存js、css、圖片等文件,而不希望緩存HTML文檔以保持獲得最新內容的情況來說,這就是個大坑
  2. 根據Application Cache的加載機制,如果僅僅修改資源文件的內容(沒有修改資源文件的路徑或名稱),瀏覽器將直接從本地離線緩存中獲取資源文件。所以在每次修改資源文件的同時,需要修改manifest文件,以觸發資源文件的重新加載和緩存。這其中,最有效的方式是修改manifest文件內部的版本註釋(所以說那句註釋相當重要)
  3. 如果資源沒有被緩存,在而沒有設置NETWORK的情況下,將會無法加載(瀏覽器不會去網絡上進行加載),所以需要使用通配符來表明除了CACHE中確定的資源以外,其他資源都需要去網絡上加載

使用iframe來避開一號坑?

網上傳言避開一號坑的方法是使用iframe來指定需要緩存的資源,而避開HTML文檔的緩存。具體做法是在HTML中嵌入一個iframe,iframe中的頁面的HTML標籤包含manifest屬性引用manifest文件,裏面定義了需要緩存的文件。這樣就會只緩存iframe中的HTML文檔,而持續更新主頁面:

<!doctype html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>主頁面</title>
    <link rel="stylesheet" href="css/style.css">
    <script src="js/javascript.js"></script>
</head>
<body>
    <iframe src="cache.html"></iframe>
</body>
</html>

可以看到,主頁面的html標籤中,並沒有引入manifest文件。只是在其中加載了一個iframe,而這個iframe所加載的頁面文檔如下:

<!DOCTYPE html>
<html manifest="manifest.appcache">
<head>
    <meta charset=utf-8 />
    <title>緩存頁面</title>
</head>
<body>
</body>
</html>

緩存頁面中引入了manifest文件,這樣瀏覽器就會緩存manifest文件中定義的資源列表,比如這裏manifest文件的內容如下:

CACHE MANIFEST
# VERSION 1.0

CACHE:
css/someStyle.css
js/someJavaScript.js

NETWORK:
*

在chrome中運行,可以在命令行中看到如下效果:

Creating Application Cache with manifest http://localhost:8000/manifest.appcache
Application Cache Checking event
Application Cache Downloading event
Application Cache Progress event (0 of 2) http://localhost:8000/css/someStyle.css
Application Cache Progress event (1 of 2) http://localhost:8000/js/someJavaScript.js
Application Cache Progress event (2 of 2)
Application Cache Cached event 

瀏覽器緩存了manifest文件中定義的資源文件,其實同時還緩存了iframe中的緩存頁面的文檔,但不會緩存主頁面,修改一下主頁面,並按F5刷新

Document was loaded from Application Cache with manifest http://localhost:8000/manifest.appcache
Application Cache Checking event
Application Cache NoUpdate event 

可以看到主頁面被更新了,但是someStyle.css和someJavaScript.js文件依舊從網絡上加載了,而沒有從cache中加載。打開chrome的chrome://appcache-internals/可以看到,裏面cache.html、someStyle.css、someJavaScript.js確實被緩存了,去掉NETWORK段,結果也是一樣

Flags       URL                                         Size (headers and data)
Master,     http://localhost:8000/cache.html            388 B
Explicit,   http://localhost:8000/css/someStyle.css     228 B
Explicit,   http://localhost:8000/js/someJavaScript.js  244 B
Manifest,   http://localhost:8000/manifest.appcache     316 B

在firefox、opera上測試也是一樣,雖然被緩存了,但依舊會從網絡上加載,而iframe的解答方法也是2011~2012年左右提出的,後來就沒有相關文章了,估計已經徹底失效了

 

Application主要是爲了構建離線緩存,使得頁面在離線模式下也能瀏覽。這比較適合一些頁面上的應用以及靜態的不經常變更的頁面。其會緩存載體頁面也是由於其機制。如果上面iframe機制實現有錯誤,或是有其他方法只緩存資源不緩存HTML文檔,也請聯繫我

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章