blob: 0b1180d3ca15f22a0b40e1dfdf8833734af8bc22 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
|
---
title: Firefox 中的離線資源
slug: Firefox_中的離線資源
tags:
- HTML5 離線
- application cache
---
<p> </p>
<div> <div> <p>原文 : <a href="/en/Using_Application_Cache" title="https://developer.mozilla.org/en/Using_Application_Cache">Using Application Cache</a></p> <p> </p> <h2 id="介紹">介紹</h2> <p> HTML5 提供了 cache 機制,使得網路應用程式能較不受到網路狀態的影響。開發人員可以藉由 Application Cache (AppCache) 的介面來定義哪些資源應當被瀏覽器儲存起來 - 如此一來即使網路斷線使用者依舊可以取得這些資源。同時,應用程式也能正確的運行即使使用者按下了「重新載入」的按鈕。</p> <p> 大抵來說,使用 Application Cache 可以取得下列好處:</p> <ul> <li>離線瀏覽:使用者可以在斷線/離線時瀏覽你的網站</li> <li>網站加速:善用 AppCache 就可以減少載入重複資源的狀況,進而加速網站讀取速度</li> <li>減少伺服器的負擔:瀏覽器僅只有在伺服器上資源發生變動時才重新抓取資料</li> </ul> <h2 id="application_cache_運作的機制">application cache 運作的機制</h2> <h3 id="啟動_application_cache">啟動 application cache</h3> <p> 啟動 AppCache 的方法很簡單,你只需要在你程式頁面中,html 元素裡指名 manifest 的位置即可,這裡有個簡單範例:</p> <div> <pre class="eval"><span class="nowiki"><html manifest="example.appcache"> </span>
...
</html>
</pre> </div> <p>manifest 指向了一個<strong> cache manifest</strong> 的檔案,他指出了在你的應用程式中哪些資源該當被瀏覽器儲存以作為快取。</p> <p> 你應該在每一個你希望瀏覽器替你儲存資源的頁面加上 manifest。瀏覽器不會自作主張的去儲存 manifest 指定以外的資源。事實上,你並不需要列出所有你想要被快取的頁面,瀏覽器會儲存使用者曾經瀏覽過的所有頁面以及你指名的那些資源。</p> <p> 某些瀏覽器 - 例如 FireFox - 會在使用者第一次讀取有使用 Application Cache 的時候提醒他們。提示訊息可能會是這樣:</p> <p>This website (<code>www.example.com</code>) is asking to store data on your computer for offline use. [Allow] [Never for This Site] [Not Now]</p> <p>The term "offline(-enabled) applications" sometimes refers specifically to applications that the user has allowed to use offline capabilities.</p> <h3 id="讀取文件">讀取文件</h3> <div> <p> Application Cache 的運作是基於讀取 manifest 檔案:</p> <ul> <li>倘若 application cache 存在,瀏覽器會直接取用本地端的快取而非經由網路請求資源。這可以加速網頁讀取。</li> <li>倘若 cache manifest 檔案被更新了,瀏覽器會下載新版的 manifest 並且依此and the resources listed in the manifest. This is done in the background and does not affect performance significantly.</li> </ul> <p> 其運作流程如下:</p> <ol> <li>當瀏覽器造訪一個有使用 AppCache 的網站時 (根據 <html> 判定),若發現自己並沒有本地快取,就按照該 manifest 建立第一版的本地快取。</li> <li>在接下來的瀏覽行為中,倘然觸及被快取的資源,瀏覽器將會直接自本地端給予回應。在此同時,瀏覽器也會傳送一個確認的事件給 <code><a href="/en/DOM/window.applicationCache" title="en/DOM/window.applicationCache">window.applicationCache</a></code> 物件,其會按照 HTTP cache rules 取回 manifest 檔案。</li> <li>假使目前本地擁有的 manifest 已經是最新,瀏覽器將會送一個「不需更新」的事件給 applicationCache 物件。所以<strong>假設任何一個在伺服器端被你註明要被快取住的物件更動了,務必改動 manifest 檔案</strong>,如此一來使用者的瀏覽器才知道要重新下載所有的資源。</li> <li>當 manifest 更新後,所有列在其中的資源會由 <code><a href="/en/nsIDOMOfflineResourceList#add.28.29" title="en/nsIDOMOfflineResourceList#add.28.29">applicationCache.add()</a></code>透過 HTTP caching rules 被重新抓取至本地的暫存快取。當一個檔案被抓到本地快取後,瀏覽器會送出 progress 的事件到 applicationCache 物件。如果發生了錯誤,瀏覽器會送出 error 事件並停止更新。</li> <li>當所有資源都被成功的取得後,他們便會被真正地移到離線時也能存取的快取區。此時,cached 事件會被發送給 applicationCache 物件。此時瀏覽器已經能顯示畫面了,未來只有當使用者重新整理頁面、手動操作或被其他程式驅動才會重新從快取中讀到瀏覽器。</li> </ol> </div> <h3 id="清除_application_cache">清除 application cache</h3> <p> 在 Chrome 中,使用者可以藉由選擇 preferences 中 <em>Clear browsing data...</em> 清除 application cache 的內容 (此外,也可以造訪 <a class="external" title="chrome://appcache-internals/">chrome://appcache-internals/</a> )。Safari 中也有類似的設計,你可以選用 preference 中的 <em>Empty cache</em> 達到一樣的目的 (但 safari 此時可能會要求你重啟瀏覽器)。</p> <p> 而 Firefox 則將這些資料放置在一般的硬碟快取中 (非在 Firefox 的 profile 中):</p> <ul> <li>Windows Vista/7: <code>C:\Users\<username>\AppData\<strong>Local</strong>\Mozilla\Firefox\Profiles\<salt>.<profile name>\OfflineCache</code></li> <li>Mac/Linux: <code>/Users/<username>/Library/Caches/Firefox/Profiles/<salt>.<profile name>/OfflineCache</code></li> </ul> <p>使用者可以透過檢查 about:cache 中 <em>Offline cache device</em> 下的資訊來得知目前狀態。</p> <p> 使用者可以清除特定網站的快取藉由 Tools -> Options -> Advanced -> Network -> Offline 中的 "Remove..." 按鈕。補充一下,以下兩個方法<strong>無法</strong>清除快取</p> <ul> <li>Clear Recent History (<a class="link-https" href="https://bugzilla.mozilla.org/show_bug.cgi?id=538595" title="https://bugzilla.mozilla.org/show_bug.cgi?id=538595">bug 538595</a>)</li> <li>Options -> Advanced -> Network -> Offline data -> Clear Now (<a class="link-https" href="https://bugzilla.mozilla.org/show_bug.cgi?id=538588" title="https://bugzilla.mozilla.org/show_bug.cgi?id=538588">bug 538588</a>)</li> </ul> <p>相關資訊亦可參考 <a href="/en/DOM/Storage#Storage_location_and_clearing_the_data" title="en/DOM/Storage#Storage location and clearing the data">clearing the DOM Storage data</a> 。</p> <div> <p> Application cache 也會有失效的時候。當伺服器端移除了 manifest 後,瀏覽器會自動清除所有在本地端的快取,並且發送 obsoleted 的事件給 <code>applicationCache 物件。這會使得 application cache 的狀態變為 </code>OBSOLETE。</p> </div> <h2 id="關於_cache_manifest_file">關於 cache manifest file</h2> <h3 id="如何引用_cache_manifest_file">如何引用 cache manifest file</h3> <p> 在 manifest 中定義資源的路徑可以分為兩種 - 相對路徑及絕對路徑 (絕對路徑:起始點是 application 所在的那層目錄)。並且,manifest 的 MIME 格式必須為 text/cache-manifest。</p> <h3 id="cache_manifest_file_的起始點">cache manifest file 的起始點</h3> <p> Manifest 文件中的資源必須以 URI 格式表示。所有列於 manifest 中的資源,他們的 scheme、host以及 port 都得和 manifest 文件一樣。</p> <h3 id="範例_1_一個簡單的_cache_manifest_file">範例 1: 一個簡單的 cache manifest file</h3> <div> <p> 這是一個簡單的範例, <code>example.appcache</code>, 我們假設他屬於 <span class="nowiki">www.example.com</span></p> <pre class="eval">CACHE MANIFEST
# v1 - 2011-08-13
# This is a comment.
<span class="nowiki">http://www.example.com/index.html</span>
<span class="nowiki">http://www.example.com/header.png</span>
<span class="nowiki">http://www.example.com/blah/blah</span>
</pre> <p> 一個 manifest 檔案可以有三種不同的段落 - <code>CACHE</code>、<code>NETWORK</code> 以及 <code>FALLBACK (容後再敘)。在 example.appcache 中我們並未指定段落名,是以所有資源會被以預設方式解析,也就是「需要被加到快取」(意義上屬於 CACHE 段)。如前所提到,資源可以用相對或絕對路徑表示(例如可以把 </code><a class=" external" href="http://www.example.com/index.html" rel="freelink">http://www.example.com/index.html</a> 改為 index.html)。</p> <p> 在這裡要特別指出被放置在註解中的「v1」字樣。顯然他表達的是版本資訊。但在 manifest 中這樣的表達方式有大用。假設今天 header.png 改變了,你只需要改動版本資訊 (或註解中的內容),則此 manifest 就會被認為有改變而使得瀏覽器重新抓取快取。當然你可以改動檔案中的其他部分,可是改變版本號是比較建議的方式。</p> <div class="warning"><strong>重要提醒:</strong> 請勿將 manifest 檔案本身也列在 manifest 內容中,否則將使瀏覽器無法辦別 manifest 是否已被更新。這將使整個 application cache 機制失效。</div> <h3 id="cache_manifest_file_中的分類段落_CACHE_NETWORK_and_FALLBACK">cache manifest file 中的分類段落: <code>CACHE</code>, <code>NETWORK</code>, and <code>FALLBACK</code></h3> <p> 在 manifest 中我們可以有三種不同的段落: <code>CACHE</code>、 <code>NETWORK 以及</code> <code>FALLBACK。</code></p> <dl> <dt><code>CACHE:</code></dt> <dd>這是預設的段落。列於 CACHE 段落下的資源列表將在使用者第一次造訪時就被加到快取中。</dd> <dt><code>NETWORK:</code></dt> <dd>列於這個段落的資源表示一定得透過網路抓取而不從快取取得。可以使用萬用字元表示內容。</dd> <dt><code>FALLBACK:</code></dt> <dd>FALLBACK 指出了一種替代關係。在這個段落裡的每一行都有兩種 URI,其一指名有網路連線時使用的資源,第二個則是斷線時使用。這兩個 URI 的根目錄必須是相對於 manifest。可以使用萬用字元表示內容。</dd> </dl> <p> 這三種不同段落可以以任意順序出現在 manifest 中,並且都可出現多次而無次數限制。</p> <h3 id="範例_2_稍微複雜點的_cache_manifest_file">範例 2: 稍微複雜點的 cache manifest file</h3> <p> 這裡我們來看看稍微複雜點的 manifest。他存在於一個虛擬的網站 <span class="nowiki">www.example.com</span>:</p> <pre class="eval">CACHE MANIFEST
# v1 2011-08-14
# This is another comment
index.html
cache.html
style.css
image1.png
# Use from network if available
NETWORK:
network.html
# Fallback content
FALLBACK:
/ fallback.html
</pre> <p> 這個範例中使用了 NETWORK 以及 FALLBACK:</p> <ul> <li>NETWORK:network.html 只能透過網路取回而不從快取。</li> <li>FALLBACK:倘若沒有網路連線就使用 fallback.html (這裡寫法意思是說無法讀取到網站的/ ,也就是無法顯示網站)</li> </ul> <h3 id="cache_manifest_file_的結構">cache manifest file 的結構</h3> <p> Cache manifest 檔案應該被定義成 text/cache-manifest 的 MIME 格式。而所有被定義成 text/cache-manifest MIME 格式的檔案將被以本章所規範的語法解析。</p> <p> 首先,Cache manifests 必須是一個 UTF-8 格式的文字檔。檔案中可以被嵌入 BOM (Byte-Order Mark)字元,舉例來說,換行會被表示成 「line feed (<code>U+000A</code>)」、「 carriage return (<code>U+000D</code>)」或 「carriage return 及 line feed both」。</p> <p> 第二,cache manifest 的第一行必須是「<code>CACHE MANIFEST」字串 (CACHE 和 MANIFEST 中間的那個空白是一個 </code>U+0020<code> 符號),其後可以任意加入 space 或 tab 字符。以這一行來說,其他被加入的字串將會被忽略。</code></p> <p> 最後,檔案中的剩餘部份是由零至多個下列所述的項目構成:</p> <dl> <dt>Blank line</dt> <dd>空白行。你可以任意用 space 或 tab 去產生新的一行。</dd> <dt>Comment</dt> <dd>註解。指的是以 # 起始的行。要注意 # 只在該行有效,你不能在後附加上其他行 (若你有多行註解,請在每行起始都加上 #)。</dd> <dt>Section header</dt> <dd>段落標頭。這裡指的是在前面我們討論過 CACHE、 NETWORK 以及 FALLBACK:</dd> </dl> <blockquote> <table class="standard-table"> <tbody> <tr> <th>Section header</th> <th>Description</th> </tr> <tr> <td><code>CACHE:</code></td> <td>其後內容指出哪些資源需要被加到瀏覽器的快取中</td> </tr> <tr> <td><code>NETWORK:</code></td> <td>其後內容指出哪些資源一定得從網路取得</td> </tr> <tr> <td><code>FALLBACK:</code></td> <td>其後內容指出資源在有網路連線及斷線時的替代關係</td> </tr> </tbody> </table> </blockquote> <dl> <dd>段落標頭行可以含有空白,但要記得在最後加上 「:」字元。</dd> <dt>Section data</dt> <dd>段落資料。其格式隨著不同段落而有所不同。在 CACHE 段落,每一行必須是符合規則的 URI 或 IRI (IRI 類似於 URI,但可使用 unicode),此外,在 CACHE 段落中不得使用萬用字元,但可自由使用空白 (前提自然是不能破壞 URI/IRI 內容)。而在 NETOWKR 段落中,其內容為符合規則之 URI/IRI,並可以使用萬用字元。最後,在 FALLBACK 段落,其每一行的構成是先寫出合於規則的 URI/IRI,接著寫出倘若網路不通時該用何資源取代。<br> <div class="note"><strong>注意:</strong>倘若使用相對路徑的 URI,那麼其相對的位置是「cache manifest 檔案的 URI」。</div> </dd> </dl> <p> Cache manifest 檔是以上述三種段落來依序判讀,是以每一段落可出現一次以上。甚至你也可以寫出內容為空的段落。</p> <h2 id="Application_cache_中的資源">Application cache 中的資源</h2> <p> Application cache 總是含有至少一個資源,並以 URI 形式敘述。下面列出資源種類,manifest 中的資源必屬其中。</p> <dl> <dt>Master entries</dt> <dd>這是一個瀏覽的入口,其引用了 manifest 檔案。</dd> <dt>Explicit entries</dt> <dd>描述 CACHE 段落的入口。</dd> <dt>Network entries</dt> <dd>描述 NETWORK 段落的入口。</dd> <dt>Fallback entries</dt> <dd>描述 FALLBACK 段落的入口。</dd> </dl> <div class="note"><strong>注意:</strong> R同一種資源可以屬於多種不同種類,例如一個 entry 可以同時是 explicit entry 和 fallback entry。</div> <p> 關於這些資源種類,下面會有更詳細的說明。</p> <h3 id="Master_entries">Master entries</h3> <p> Master entries 是一種在他們 {{ HTMLElement("html") }} element 中含有 {{ htmlattrxref("manifest","html") }} attribute 的 HTML 檔。舉例來說,如果我們說我們有一個 <code><a class="linkification-ext external" href="http://www.foo.bar/entry.html" title="Linkification: http://www.foo.bar/entry.html">http://www.example.com/entry.html</a> 的 HTML 檔,其內容為:</code></p> <pre><html manifest="example.appcache">
<h1>Application Cache Example</h1>
</html>
</pre> <p>如果 <code>entry.html</code> 並未被列在 <code>example.appcache</code> 中,幫妳拜訪 <code>entry.html</code> 時,他就會被加到 application cache 中,並被指明為一個 master entry。</p> <h3 id="Explicit_entries">Explicit entries</h3> <p> 這指出了哪些檔案需要被存到快取中。</p> <h3 id="Network_entries">Network entries</h3> <p> 這指出了哪些檔案一定得透過網路取得。可以看成是列出了一張線上白名單 (online whitelist),提示了有些東西必須得透過網路向伺服器抓取。這有很多好處,其中一個好處是可以避開些安全漏洞,避免某些認證結果從本地端讀取而造成危險 (如果這個認證結果被竄改的話 ... )。</p> <p> 這裡有個例子,你可以要求執行的腳本一定得透過網路向伺服器抓取:</p> <pre>CACHE MANIFEST
NETWORK:
/api</pre> <div class="note"><strong>注意:</strong> Simply有人可能會覺得「一定向伺服器抓取資料」的這件事也可以透過把他們放置在 master entry 達成,但事實上 master entry 會被加入到 application cache 中。</div> <h3 id="Fallback_entries">Fallback entries</h3> <p> Fallback entry 的使用時機在於網路可能斷線。直接看例子,當我們說有個 manifest (<code><a class=" external" href="http://www.example.com/example.appcache" rel="freelink">http://www.example.com/example.appcache</a>),其檔案內容是:</code></p> <pre>CACHE MANIFEST
FALLBACK:
example/bar/ example.html
</pre> <p>任何企圖抓取 <code><a class=" external" href="http://www.example.com/example/bar/" rel="freelink">http://www.example.com/example/bar/</a></code> 或其子資料夾的請求若是失效,瀏覽器會讀取 <code>example.html</code> 作為替代。</p> <h2 id="Cache_的狀態">Cache 的狀態</h2> <p> 每一個 application cache 都有一個 <strong>state</strong>,表明目前在瀏覽器端的狀態。共用同一個 manifest URI 的 cache 擁有一樣的狀態。狀態的種類如下:</p> <dl> <dt><code>UNCACHED</code></dt> <dd>這是特殊的一個狀態,代表 cache 物件尚未初始化。</dd> <dt><code>IDLE</code></dt> <dd>代表 cache 並非處於更新中的狀態。</dd> <dt><code>CHECKING</code></dt> <dd>目前正在向伺服器端抓取 manifest 檔案以確認是否接下來要有更新資源的動作。</dd> <dt><code>DOWNLOADING</code></dt> <dd>因為 manifest 的更新,資源已經被下載到本地端的快取中。</dd> <dt><code>UPDATEREADY</code></dt> <dd>有一個新版的 application cache 是可用的狀態。這搭配著 <code>updateready</code> 的事件。相對於 <code>cached</code> 事件,他的意思是有新版的更新已經在本地,但尚未呼叫 <code>swapCache()函式。</code></dd> <dt><code>OBSOLETE</code></dt> <dd>Application cache 群組現在處於過時的狀態。</dd> </dl> <h2 id="測試_cache_manifest_的更新">測試 cache manifest 的更新</h2> <p> 你可以經由撰寫 JavaScript 程式來關注是否 manifest 檔有所更新。但未免在你漏失在 Listener 完成註冊之前就完成的事件,務必檢查 <code>window.applicationCache.status。如下所示:</code></p> <pre class="brush: js">function onUpdateReady() {
alert('found new version!');
}
window.applicationCache.addEventListener('updateready', onUpdateReady);
if(window.applicationCache.status === window.applicationCache.UPDATEREADY) {
onUpdateReady();
}</pre> <p> 倘若你想手動的去測試 manifest 檔案是否更新,你可以使用 <code>window.applicationCache.update()。</code></p> <h2 id="注意_!!!">注意 !!!</h2> <ul> <li>當 application cache 的機制被啟動,程式撰寫員無法簡單的透過更新資源本身就取得目前伺服器上最新的版本 (或許你已經自本地端快取讀出資源了!)。你必須在瀏覽器讀取資源之前就更新 manifest 檔。這個動作可以透過 <code>window.applicationCache.swapCache() 達到,但在此刻已經被讀取的資源將不受影響。最好的方式是重新刷新頁面。</code></li> <li>一個好的主意是是為你伺服器上所有副檔名為 appcache 的檔案設定為已經失效 (set expires headers)。這可以避免 manifest 被加到快取中的風險。以 Apache 為例,你可以這麼做:<br> <code>ExpiresByType text/cache-manifest "access plus 0 seconds"</code></li> </ul> <h2 id="支援_Application_Cache_的瀏覽器們">支援 Application Cache 的瀏覽器們</h2> <p>{{ CompatibilityTable() }}</p> <div id="compat-desktop"> <table class="compat-table"> <tbody> <tr> <th>Feature</th> <th>Chrome</th> <th>Firefox (Gecko)</th> <th>Internet Explorer</th> <th>Opera</th> <th>Safari</th> </tr> <tr> <td>Basic support</td> <td>4.0</td> <td>3.5</td> <td>10.0</td> <td>10.6</td> <td>4.0</td> </tr> </tbody> </table> </div> <div id="compat-mobile"> <table class="compat-table"> <tbody> <tr> <th>Feature</th> <th>Android</th> <th>Firefox Mobile (Gecko)</th> <th>IE Mobile</th> <th>Opera Mobile</th> <th>Safari Mobile</th> </tr> <tr> <td>Basic support</td> <td>2.1</td> <td>{{ CompatUnknown() }}</td> <td>{{ CompatNo() }}</td> <td>11.0</td> <td>3.2</td> </tr> </tbody> </table> </div> <p>附註:先於 3.5 版以前的FireFox 忽略了 manifest 檔案中 NETWORK 以及 FALLBACK 的部分。</p> <h2 id="參考資料">參考資料</h2> <ul> <li><a class="external" href="http://www.html5rocks.com/en/tutorials/appcache/beginner/" title="http://www.html5rocks.com/en/tutorials/appcache/beginner/">HTML5Rocks - A Beginner's Guide to Using the Application Cache</a></li> <li><a class="external" href="http://appcachefacts.info/" title="http://appcachefacts.info/">appcachefacts.info</a> - detailed information on AppCache idiosyncrasies</li> <li><a class="external" href="http://hacks.mozilla.org/2010/01/offline-web-applications/" title="http://hacks.mozilla.org/2010/01/offline-web-applications/">offline web applications</a> at hacks.mozilla.org - showcases an offline app demo and explains how it works.</li> <li><a class="external" href="http://www.whatwg.org/specs/web-apps/current-work/multipage/offline.html#offline" title="http://www.whatwg.org/specs/web-apps/current-work/multipage/offline.html#offline">HTML 5 working draft: Offline web applications</a></li> <li><a class="external" href="http://developer.teradata.com/blog/js186040/2011/11/html5-cache-manifest-an-off-label-usage" title="http://developer.teradata.com/blog/js186040/2011/11/html5-cache-manifest-an-off-label-usage">HTML5 Cache Manifest: An Off-label Usage</a></li> <li>{{ interface("nsIApplicationCache") }}</li> <li>{{ interface("nsIApplicationCacheNamespace") }}</li> <li>{{ interface("nsIApplicationCacheContainer") }}</li> <li>{{ interface("nsIApplicationCacheChannel") }}</li> <li>{{ interface("nsIApplicationCacheService") }}</li> <li>{{ interface("nsIDOMOfflineResourceList") }}</li> <li><a class="external" href="http://www.ibm.com/developerworks/web/library/wa-ffox3/">Get ready for Firefox 3.0 - A Web developer's guide to the many new features in this popular browser, especially the offline application features</a> (IBM developerWorks)</li> </ul> <p>{{ HTML5ArticleTOC() }}</p> <p>{{ languages( { "es": "es/Recursos_offline_en_firefox", "fr": "fr/Ressources_hors_ligne_dans_Firefox", "ja": "ja/Offline_resources_in_Firefox", "pl": "pl/Zasoby_offline_w_Firefoksie", "zh-tw": "zh_tw/Offline_resources_on_Firefox" } ) }}</p> </div> </div>
</div>
|