1. 程式人生 > >[html5]離線儲存

[html5]離線儲存

H5的一個重要特性就是離線儲存,所謂的離線儲存就是將一些資原始檔儲存在本地,這樣後續的頁面重新載入將使用本地資原始檔,在離線情況下可以繼續訪問web應用,同時通過一定的手法(更新相關檔案或者使用相關API),可以更新、刪除離線儲存等操作;

H5的離線儲存使用一個manifest檔案來標明哪些檔案是需要被儲存的,使用如 <html manifest='offline.manifest'> 來引入一個manifest檔案,這個檔案的路徑可以是相對的,也可以是絕對的,如果你的web應用很多,而且希望能集中管理manifest檔案,那麼靜態檔案伺服器是個不錯的選擇。

對於manifest檔案,要求:檔案的mime-type必須是 text/cache-manifest型別

。如果你是JAVA工程,在你的web.xml中配置請求字尾為manifest的格式:

<mime-mapping>
        <extension>manifest</extension>
        <mime-type>text/cache-manifest</mime-type>
</mime-mapping>  
這樣可以控制請求到的manifest檔案格式為text/cache-manifest的。

 manifest檔案的格式:

CACHE MANIFEST
# 這一句必須存在,而且必須放在頭部
# 指明快取入口
CACHE:
index.html
style.css
images/logo.png
scripts/main.js
# 以下資源必須線上訪問
NETWORK:
login.php
# 如果index.php無法訪問則用404.html代替
FALLBACK:
/index.php /404.html

其中 CACHE 不是必須存在的,可以直接在 CACHE MANIFEST 行之下直接寫需要快取的檔案,在這裡指明的檔案將被快取到瀏覽器本地。在NETWORK之下指明的檔案,是強制必須通過網路資源獲取的,在FALLBACK下指明的是一種失敗的回撥方案,比如上述index.php無法訪問,那麼就發出404.htm請求

這樣幾步就可以完成對離線儲存的支援。接下來要思考的,是如何更新離線儲存?

當用戶本地再次聯網的時候,本地的離線儲存資源需要檢查是否需要更新,這個更新過程,也是通過manifest的更新來控制的,更新了manifest檔案,瀏覽器會自動的重新下載新的manifest檔案並在下一次重新整理頁面

的時候進行資原始檔的重新請求(第三次重新整理替換本地快取為最新快取),而且這個請求是全域性性的,也就是所有在manifest快取列表中的檔案都會被請求一次,而不是單獨請求某個特定修改過的資原始檔,因為manifest是不知道哪個檔案被修改過了的。

對於全域性更新的擔心是不必要的,因為對於沒有更新過的資原始檔,請求依舊是304響應,只有真正更新過的資原始檔才是200.

所以控制離線儲存的更新,需要2個步驟,一是更新資原始檔,二是更新manifest檔案,特別的,更新manifest檔案是不需要修改什麼特定內容的,只要是這個檔案隨意一處被修改,那麼瀏覽器就會感知,對於我們的資原始檔通常名稱是固定的,比如xxx.css,更新內容不會帶有檔名更新的情況下,需要更新manifest檔案怎麼操作呢?一個比較好的方式是更新任意一處# 開頭的註釋即可,其目的只是告訴瀏覽器這個manifest檔案被更新過。

以上的這些內容,其更新操作都是瀏覽器自動完成的。同樣的,W3C定義了離線儲存的API規範:http://www.whatwg.org/specs/web-apps/current-work/#applicationcache

提供瞭如下API:

// 更新,一般來說更新下載是通過使用者代理(如瀏覽器)自動完成的,但是這個方法適用於一些長期開啟的頁面,比如郵件系統,可能這個頁面是長期開啟的,而不會有重新整理動作,所以這個就比較適合做自動更新下載
void update();
// 取消 
void abort();
// 替換快取內容 ,對於manifest檔案的改變,通常是下一次的重新整理才會觸發下載更新,第三次重新整理才會切換使用新的快取檔案,通過這個方法,可以強制將快取替換
void swapCache();
提供瞭如下的事件:
Event handler 	    Event handler event type
onchecking 	    checking
onerror 	            error
onnoupdate 	    noupdate
ondownloading 	    downloading
onprogress 	    progress
onupdateready 	    updateready
oncached 	            cached
onobsolete 	    obsolete

最後說一個對於manifest比較特別的地方:對於某個檔案a.htm,其中有 <html manifest='a.manifest'> ,那麼離線儲存中,會自動將a.htm加入到列表中,這意味著a.htm的再次重新整理將從本地快取中獲取,這樣的機制從官方得到的答覆是“特別的設計”,而對我們來說,這種強加的特性在後續的開發過程中會有不少問題,比如:

1、如何計算PV UV,由於當前頁面被強制加入manifest,那麼PV 和UV的統計,成了一個難題,因為請求不再是傳送到伺服器;

2、對於某個使用manifest的檔案,其帶有的引數可能是隨機性的統計引數,如sid=123sss, sid=234fff ,尤其是比如商品詳情的id欄位等,這樣每個頁面都自動加入到manifest中,將會帶來很大的儲存開銷,而且是毫無意義的;

所以伴隨而來的,是如何在現有的體系架構下進行資料統計的難題,一個常規的方案是進入離線儲存頁面後自動發出ajax請求,以告知伺服器統計PV UV;


對於第二個問題,可能就比較棘手,但是將GET請求的方式改成POST的方式確實是個解決問題的方案。