英文原址:https://developer.mozilla.org/en/Using_Application_Cache
HTML5支持应用资源的离线存储;文件被存储在应用缓存中--从包括web应用的缓存清单(cache manifest)中获取的一系列资源。
应用缓存(The application cache)
每个web应用的资源仓库用它自己的应用缓存。因为应用程序可以共享资源(甚至同一个仓库URI),每一个应用的缓存有一个单独的所有资源的拷贝。这些缓存是有版本号标识的;每次web 应用程序被在线访问时,如果发生了更新,一个应用程序的新版本号被同步到应用缓存中。这个新版本号会在下一次访问这个站点的时候被使用。
应用缓存如何工作(How the application cache works)
应用缓存在加载文档的时候更改正常的进程;如果应用缓存已经存在,程序直接从缓存中加载资源,无需访问网络,加速页面加载。web应用程序接着会检测清单(manifest)是否在服务端被更新,如果有,下载一个新版本的缓存的Web应用程序。这些都是在后台运行的并且影响不是很明显。
应用缓存可以变为过期(obsolete)。如果清单在服务端中被清除,浏览器会所有使用那个清单的应用缓存,然后发出"obsolete"指令给应用缓存对象。接着应用缓存的状态被设置为"obsolete"。
缓存状态(Cache states)
每个应用缓存都有一个状态(state),它指示了缓存的当前环境。使用同一个清单URI的缓存共同使用一个同一个缓存状态,状态(state)会有以下取值:
UNCACHED(0)
一个特殊的值指示应用缓存对象没有被完全初始化
IDLE(1)
应用缓存当前没有在更新的进程中
CHECKING(2)
清单被获取并检查更新情况
DOWNLOADING(3)
由于更改了资源清单,资源被下载添加到缓存中
UPDATEREADY(4)
有一个应用缓存的新版本号有效。一个新的更新被下载但是还没有使用swapCache()方法激活的时,会有一个updateready指令代替cached指令被触发。
OBSOLETE(5)
应用缓存组过时
应用缓存的资源(Resources in the application cache)
应用缓存中的资源通过一个指向清单文件(一个使用*.manifest扩展的文件)的URI来标识。这个文件在<html>元素中的mainfest属性被引用。清单在应用缓存更新进程中下载并被处理。各条目必须有和清单一样的组织纲目,主机名和端口。缓存会包含至少一份用URI标识的资源。所有的资源符合下述以下类别:
主条目(Master entries):
这些是添加到缓存中的资源,因为一个被用户访问的浏览环境包括一个在缓存中用manifest属性标识的文档
明确条目(Explicit entries):
在缓存的清单中列出的资源
备用条目(Fallback entries):
在缓存的清单中作为备用条目的资源
注意:资源可以用多种类别作为标签,并且因此能够作为多种条目分类。比如,一个条目可以是Explicit entries和Fallback entries。
主条目(Master entries)
主条目是任意在<html>标签中包含mainfest属性的html文件。比如,我们有文件http://www.example.com/entry.html,内容如下:
<html manifest="example.manifest">
<h1>Application Cache Example</h1>
</html>
如果entry.html没有包含在清单中,访问entry.html页面会使entry.html被作为主条目添加到应用缓存中。
备用条目(Fallback entries)
备用条目是在尝试加载一个资源失败的时候使用的。比如,想象有一个缓存清单位于http://www.example.com/example.appcache,内容如下:
CACHE MANIFEST
FALLBACK:
example/bar/ example.html
任何对http://www.example.com/example/bar/或者它的子目录和内容的访问都会引起一个尝试下载请求资源的请求。如果尝试失败,由于网络失败或者服务器的某种错误,example.html会被替代加载。
网络条目(Network entries)
在网络下列出的条目:可能包含0或多个web应用程序的在线访问资源。本质上也就是说,一份"在线白名单"。这些在网络中指定的URI从服务端下载而不是缓存中。这样让浏览器的安全模式通过限制只可以访问允许资源的方法来保护用户,防止的潜在安全违规行为。
注意:在线白名单在Firefox3.5版本之前被忽略。
例如,你可以像以下这么使用,来加载和执行脚本和其他从服务端而不是缓存中的代码:
CACHE MANIFEST
NETWORK:
/api
这样保证那些包含http://www.example.com/api/
子路径的加载资源的请求始终通过网络,而不是尝试去访问缓存。
注意:在清单文件中简单的省略主条目(那些在<html>元素中有manifest属性的文件)不会有相同的结果,因为主条目会被随后而来的应用缓存服务添加
缓存清单(The cache manifest)
缓存清单文件必须使用text/cache-manifest这种MIME类型,而且使用这种MIME类型的资源必须遵守在这里定义的应用缓存清单的语法。缓存清单是UTF-8格式的文本,可选包含BOM字符集。新的一行可能是换行符(U+000A),回车符(U+000D),或者回车(U+000A)和换行符(U+000D)都有
缓存清单第一行必须包括字符串CACHE MANIFEST(在两个单词之间用单独的U+0020空格),后面跟一行0或者多个空格或tab字符。任何其他的文本在这行都会被忽略。
缓存清单剩下部分必须由以下0个或多个行组成:
空白行
你可以使用0个或多个空格和tab组成的空白行。
注释
注释可以有0个或多个空格或tab后面跟着单独的#号字符,后面再接着0或多个字符
注释只能用于独自一行中,不能放在其他行后面。也就意味着你不能指定片段标识符
章节头(Section header)
章节头指定缓存清单的哪一个章节是可操纵的。以下是3个可能的章节头:
CACHE:转换成明确条目。这是默认的。
FALLBACK:转换成备用条目。
NETWORK:转换成在线白名单章节。
章节头可能包括空格,但是章节名一定要有冒号(:).
章节数据(Section data)
不同的章节格式不同。在明确(explicit)条目中,每行是对缓存资源有效的URI或者IRI引用(不允许在章节里出现通配符),在URI或IRI前面或后面允许出现空白字符。在备用(Fallback)章节中,每一行是一个有效的URI或IRI资源引用,后面的备用资源在不能连接服务端的时候进行服务。在网络(NetWork)章节中,每一行是要从网络中获取的资源的URI或IRI引用(通配符*可以在这一章节中使用)
缓存清单中每个章节头(section header)可以被使用多次,章节允许为空。
注意:相对的URI是相对于缓存清单的URI,而不是相对清单的文档URI。
一个缓存清单的例子(A sample cache manifest)
下面是一个简单的缓存清单的例子,假设example.applicache在站点www.example.com上
CACHE MANIFEST
#v1 -2011098013
#这是注释
http://www.example.com/index.html
http://www.example.com/header.png
http://www.example.com/blah/blah
在这个例子中没有章节头(section header ),所以所有的数据行默认为明确(explicit)章节。你也可以指定相对的URL(例如:index.html)
在这里注释"v1"有很好的理由。因为缓存只在清单有字节改变的时候更新。如果你更改了资源(例如,用新的内容更新了图像header.png),你需要改变清单文件内容以便让浏览器知道它需要刷新缓存(而且由于header.png一直在缓存文件里,你需要修改一些东西)。你可以对清单做任何修改,但是有一个版本数字是一个建议的最好做法。
重要的是:不要在缓存清单中知道清单自己,除非你断定几乎不可能去通知浏览器一个新的清单可用。
下面是一个相同更加完整的缓存清单,假设在站点www.example.com。这个例子又使用了备用(FALLBACK)和网络(NETWORK)章节去指定network.html也必须经常在网络中被检索,fallback.html应该作为一个备用资源服务,比如在不能连接到服务端的情况下。
CACHE MANIFEST
# v1 2011-08-14
# 这是注释
index.html
cache.html
style.css
image1.png
#Fallback content
FALLBACK:
/ fallback.html
#Use from network if available
NETWORK:
network.html
指定清单文件(Specifying a cache manifest)
要使用应用缓存,你需要像下面这样使用<html>元素的manifest属性:
<html manifest="example.manifest">
...
</html>
有些像Firefow这样的浏览器会在第一时间给用户展示通知栏"This website(www.example.com) is asking to store data on your computer for offline use.[Allow][Nerver for This Site][Not Now]".术语"离线应用(Offline(-enabled) applications)"有时指明确用户是否允许使用应用的离线功能。
更新进程(The update process)
1、当浏览器访问一个包含manifest 属性的文档而应用缓存还不存在的时候,浏览器会加载文档然后获取清单文件列出的所有条目,同时创建应用缓存的第一个版本。
2、随后访问这个文档会触发浏览器去加载文档和其他应用缓存中清单文件确定的资产(而不是从服务端),此外浏览器会发出checking指令给window.applicationCache对象,然后按照恰当的HTTP缓存规则获取清单文件,如果清单中缓存下来的拷贝是最新的,那么noupdate指令会发送给applicationCache,同时结束更新进程。(所以如果你更改了服务端的资源,你需要同时更改清单文件以便使浏览器知道它需要重新获取所有的资源)
3、如果清单文件发生改变,清单中的所有文件--以及通过调用applicationCache.add()添加到缓存中的文件--按照恰当的HTTP缓存规则放入到临时缓存。对于放入到临时缓存中的每个文件,一个progerss指令会被发送给applicationCache对象。如果发生错误,会发送一个error指令,同时更新停止。
4、成功取完所有的文件之后,这些文件会自动移动到真正的离线缓存中,同时发送一个cached指令给applicationCache对象。由于文档已经从缓存中加载到浏览器,更新过的文档不会被呈现出来直到文档被重新加载(无论是手动还算程序操作)
更新测试(Test for updates)
做个测试来看一下是否可以通过Javascript来程序操作一个可用的更新过的缓存清单。缓存已经在检测更新的脚本使用之前被更新,脚本会时常检测window.applicationCache.status.
function onUpdateReady(){
alert('found new version!");
}
window.applicationCache.addEventListener('updateready', onUpdateReady);
if(window.applicationCache.status == window.applicationCache.UPDATEREADY){
onUpdateReady();
}
你可以使用window.applicationCache.update()手动测验一个新的清单。
陷阱(Gotchas)
1、由于各个应用都使用同一个缓存,简单地更新web服务下的页面并不能完全更新那些需要缓存的文件。在这些文件使用它们新的资源之前会要求更新清单。这个可以通过调用window.applicationCache.swapCache()完成,但是不会影响到已经加载下来的资源。为了确保资源是从应用缓存的新版本中下载的,刷新页面比较理想
2、有个好的建议,在你的web服务端上为*.appcache文件设置过期的头部使文件立刻过期以避免缓存清单文件的风险。比如,在Apache你可以像下面这样配置:
ExpiresByType text/cache-manifest "access plus 0 seconds"
存储位置和清除离线缓存(Storage location and clearing the offline cache)
在Chrome中你可以在perferences中选择"Clear browsing data..."或者通过访问chrome://appcache-internals/来清除离线缓存。Safari在preferences里有一个类似"Empty cache"的设置,浏览器重启时也会发出请求的。
Firefox中,离线缓存数据被单独存储在Firefox的预置文件中--靠近正规的磁盘缓存:
Windows Vista/7下: C:\Users\<username>\AppData\Local\Mozilla\Firefox\Profiles\<salt>.<profile name>\OfflineCache
Mac/Linux下:
/Users/<username>/Library/Caches/Firefox/Profiles/<salt>.<profile name>/OfflineCache
Firefox中离线缓存的当前状态可以在about:cache页中检测到。(在"Offline cache device"标题中)。
离线缓存不能通过清除最近历史记录清除(bug 538595)。
离线缓存不能这样清除Tools -> Options -> Advanced -> Network -> Offline data -> Clear Now (bug 538588).
离线缓存应当这样清除,对于每个站点,使用Tools -> Options -> Advanced -> Network -> Offline data,点击"Remove..."