欢迎各位兄弟 发布技术文章

这里的技术是共享的

You are here

Application cache

shiping1 的头像

Application cache 是 HTML5 中在规范完整性上比较糟糕的特性之一,规范上的不到位导致浏览器厂商在实现上也存在些许差异,而产生本文档的目的即让开发者们知晓那些潜规则,摆脱问题的困惑与束缚,正确的使用应用缓存真正让 Web 加速。

Fact :设计 Appcache 的目的虽是能让 Web 应用能在离线的情况的运行而无需要求连接网络,但同时 Appcache 也可在网络在线的情况的使用,如此来减少页面需要加载的资源数量来提速页面,速度上将是一个数量级的提升。

Fact :服务器返回 manifest 文件的MIME类型必须是 text/cache-manifest, 否则虽配置 manifest 文件但 Appcache 功能并不会启用。

建议 manifest 文件以 .appcache 为文件后缀名,
并在 Web 服务器中添加 MIME 类型类型,如在 Apache 的.htaccess 配置中添加:
AddType text/cache-manifest .appcache

Fact :Appcache 的 manifest 文件有三个可选的配置项目: CACHE, NETWORK, FALLBACK。

CACHE 项配置所有需要存储在本地应用缓存中的资源文件,浏览器会在页面加载完
成后即时的自动在后台下载。如果浏览器之前已经下载过CACHE列表中的某个资源则
不会再次下载。

NETWORK 项配置与 CACHE 正相反,它告诉浏览器哪些资源要求是在有网络的环境下,
如后台的API接口调用,可以配置在 NETWORK 项。 如我们的接口地址是 http://example.com/api/
前缀格式的URL,则只需配置其URL的前缀格式,无需列出所有URL,浏览器会自动去匹配。

如果我们需要配置为所有的URL地址为CACHE或NETWORK,Chrome 与 Safari 要求用户
配置为 *,Firefox要求为 http://* 和 https://*,兼容上考虑我们可在配置
中分别加入 *,http://* 和 https://* 使其在所有浏览器中都被识别。

FALLBACK 项配置为告诉浏览器在离线环境下或服务器故障时这些网络资源不可用
时的使用哪些替代资源。

Fact :在SSL安全连接下,所有在 manifest 配置的资源列表需符合同源策略。即所有的地址都必须是相对地址。但Chrome除外,在SSL下,即使有非同源的资源,Chrome仍旧会下载至应用缓存中。

Fact :manifest 文件任何的改变包括注释都会触发浏览器更新应用缓存中的所有资源。通常 manifest 的配置策略在每次发布是并不会有改变,为了更新应用缓存我们会在 manifest 的中加入版本注释,在下次发布中则修改 # version 1 注释来知会浏览器更新应用缓存。

CACHE MANIFEST
# version 1
CACHE
/logo.png
...

Fact :当需要更新已存在的应用缓存时,浏览器会向服务器发送标准的 If-Modified-Since 请求头,当远程的资源未改变与本地缓存一致时,浏览器则不再重新下载。浏览器不会自动去检测列表中资源,必须手动去改变 manifest 文件来触发,我们推荐通过改变 manifest 中的版本注释来触发检测,简单且有效。

Fact :manifest 中的任何资源的改变只在的下次页面加载中生效。因为如页面已经被缓存,浏览器会立即从缓存中获取资源,然后才开启后台进程去检测 manifest 文件中是否有资源需要被刷新。所以最新版本的资源只会在浏览器下次启动时被从缓存中获取。我们可以绑定 updateready 事件来获知后台更新完新版本资源的时机,然后提示用户是否需重新加载页面:

if (window.applicationCache) {
    applicationCache.addEventListener('updateready', function() {
        if (confirm('页面更新完成,是否重新加载?')) {
            window.location.reload();
        }
    });
}

老版本如能提供正常的功能体验的情况下,建议在当次打开时继续使用老版本,或在页面顶部提醒用户避免突然的弹窗确认。

Fact :如在 CACHE 项配置的任何一个资源浏览器在检索时服务器返回 404 或 500 时,此时整个 CACHE 配置将被忽略。浏览器会保证 CACHE 项的完整性,并在下次页面加载时重新拉取 manifest 文件继续按此原则检索资源,直到 CACHE 项中配置的资源全部可用时。

Fact :在每次页面加载后,浏览器都会去检索当前页面的 manifest 文件是否可用,如服务器返回 404 或 500,所有已经被缓存在本地的离线资源都会被忽略。

Fact :即使我们没有在 manifest 文件中加入当前包含 manifest 的页面地址,浏览器会默认把其添加到应用缓存。这意味着我们无需在 manifest 中列出每个网页地址,因为只要是用户访问的每个页面都包含 manifest 文件浏览器会隐式的将其添加进应用缓存中。

Fact :Chrome 可以在地址中输入 chrome://appcache-internals/ 列出已经被浏览器缓存的网站,并可以查看所有网站的应用缓存占用空间,最后修改时间,还可直接对其进行删除。

Fact :Firefox 对于请求返回头配置为 Cache-control: no-store 的资源一律不缓存,即使是显式配置在 manifest 文件中。

Fact :当应用需要使用 appcache 时,Firefox 会在首次打开应用时询问用户是否授权使用。

Fact :Android Webview 默认没有开启 Appcache,可通过如下配置在Webview中支持Appcache功能

webView.getSettings().setDomStorageEnabled(true);
// 设置缓存总容量为 8 mb
webView.getSettings().setAppCacheMaxSize(1024*1024*8);
// 缓存路径
String appCachePath = getApplicationContext().getCacheDir().getAbsolutePath();
webView.getSettings().setAppCachePath(appCachePath);
webView.getSettings().setAllowFileAccess(true);
webView.getSettings().setAppCacheEnabled(true);
// 设置缓存策略
webView.getSettings().setCacheMode(WebSettings.LOAD_DEFAULT);

参考资源

© 2012 Mark Christian & Dustin Diaz. License: CC Attribution 3.0.


来自 http://madscript.com/html5/appcache-facts/

 

简介

HTML5 提供一种 应用缓存 机制,使得基于web的应用程序可以离线运行。开发者可以使用 Application Cache (AppCache接口设定浏览器缓存的数据并使得数据离线有效。 在处于离线状态时,即使用户点击刷新按钮,应用也能正常加载与工作。

使用应用缓存可以得到以下益处:

  • 离线浏览: 用户可以在离线状态下浏览网站内容。
  • 更快的速度: 因为数据被存储在本地,所以速度会更快.
  • 减轻服务器的负载: 浏览器只会下载在服务器上发生改变的资源。

应用缓存如何工作

开启应用缓存

若想为应用开启应用缓存,你需要在应用页面中的 <html> 元素上增加 manifest 特性,请看下面的例子:
<html manifest="example.appcache"> 
  ...
</html>

manifest 特性与 缓存清单(cache manifest) 文件关联,这个文件包含了浏览器需要为你的应用缓存的资源(文件)列表。

你应当在每一个意图缓存的页面上添加 manifest 特性。浏览器不会缓存不带有manifest 特性的页面,除非这个页面已经被写在清单文件内的列表里了。你没有必要添加所有你意图缓存的页面的清单文件,浏览器会将用户访问过的并带有 manifest 特性的所有页面添加进应用缓存中。

有些浏览器,比如说firefox,当用户首次加载一个需要使用应用缓存的应用时,会显示一个提示栏。提示信息如下:

该站点 (www.example.com) 请求在你的电脑上存储数据以供离线使用。[允许] [对此站点永不允许] [暂时不允许]

术语 「offline(-enabled) applications」 很多情况下指用户已经允许使用离线存储的程序。

加载文档

使用了应用缓存机制以后加载文档的顺序是这样的:

  • 如果应用缓存存在,浏览器直接从缓存中加载文档与相关资源,不会访问网络。这会提升文档加载速度。
  • 浏览器检查清单文件列出的资源是否在服务器上被修改。
  • 如果清单文件被更新了, 浏览器会下载新的清单文件和相关的资源。 这都是在后台执行的,基本不会影响到webapp的性能。

下面详细描述了加载文档与更新应用缓存的流程:

  1. 当浏览器访问一个包含 manifest 特性的文档时,如果应用缓存不存在,浏览器会加载文档,然后获取所有在清单文件中列出的文件,生成应用缓存的第一个版本。
  2. 对该文档的后续访问会使浏览器直接从应用缓存(而不是服务器)中加载文档与其他在清单文件中列出的资源。此外,浏览器还会向 window.applicationCache 对象发送一个 checking 事件,在遵循合适的 HTTP 缓存规则前提下,获取清单文件。
  3. 如果当前缓存的清单副本是最新的,浏览器将向 applicationCache 对象发送一个 noupdate 事件,到此,更新过程结束。注意,如果你在服务器修改了任何缓存资源,同时也应该修改清单文件,这样浏览器才能知道它需要重新获取资源。
  4. 如果清单文件已经改变,文件中列出的所有文件—也包括通过调用 applicationCache.add() 方法添加到缓存中的那些文件—会被获取并放到一个临时缓存中,遵循适当的 HTTP 缓存规则。对于每个加入到临时缓存中的文件,浏览器会向 applicationCache 对象发送一个 progress 事件。如果出现任何错误,浏览器会发送一个 error 事件,并暂停更新。
  5. 一旦所有文件都获取成功,它们会自动移送到真正的离线缓存中,并向  applicationCache 对象发送一个 cached 事件。鉴于文档早已经被从缓存加载到浏览器中,所以更新后的文档不会重新渲染,直到页面重新加载(可以手动或通过程序).

存储位置与清除离线缓存

在 Chrome 中,你可以在设置中选择 「清除浏览器数据...」 或访问 chrome://appcache-internals/ 来清除缓存。Safari 在设置中有一个类似的"清空缓存" 选项,但是需要重启浏览器后才能生效。

在 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 页面(在「离线缓存设置」标题下)来检查离线缓存的当前状况。 若想单独清除每个网站的离线缓存,可以使用 工具 -> 选项 -> 高级 -> 网络 -> 离线数据中的「删除」按钮。

在 Firefox 11 之前,无论是 工具 -> 清除近期历史 还是 工具 -> 选项 -> 高级 -> 网络 -> 离线数据 -> 立即清除 都无法清除离线缓存。这个问题已经被修复。(点击 “立即清除” 只是将缓存文件清除掉,并没将缓存清单删除,所以下次载入页面是更新缓存,而非创建缓存,意味着cached和updateready事件触发机制不同,如果想要清除掉缓存清单,只能选中域,然后点击移除)

另请参阅 清除 DOM 存储数据

应用缓存可以变成废弃的。如果从服务器上移除一个应用的清单文件,浏览器将会清除所有清单中列出的应用缓存,并向 applicationCache 对象发送一个「obsolete」事件。这将使得应用缓存的状态变为 OBSOLETE。

缓存清单文件

引用一个缓存清单文件

web 应用中的 manifest 特性可以指定为缓存清单文件的相对路径或一个绝对 URL(绝对 URL 必须与应用同源)。缓存清单文件可以使用任意扩展名,但传输它的 MIME 类型必须为 text/cache-manifest。

 

注意:在 Apache 服务器上,若要设置适用于清单(.appcache)文件的 MIME 类型,可以向根目录或应用的同级目录下的一个 .htaccess 文件中增加 AddType text/cache-manifest .appcache 。

 

缓存清单文件中的记录

缓存清单文件是一个纯文本文件,它列出了所有浏览器应该缓存起来的资源,以便能够离线访问。资源使用 URI 来标识。在缓存清单文件中列出的所有记录必须拥有相同的协议、主机名与端口号。

示例 1:一个简单的缓存清单文件

下面是一个简单的缓存清单文件,example.appcache,适用于一个虚拟的网站 www.example.com

CACHE MANIFEST
# v1 - 2011-08-13
# This is a comment.
http://www.example.com/index.html
http://www.example.com/header.png
http://www.example.com/blah/blah

一个缓存清单文件可以包含三段内容 (CACHE, NETWORK, 和 FALLBACK, 下面详细讨论)。 在上面的例子中,没有段落标题,因此所有数据行都认为是属于显式 (CACHE) 段落,这意味着浏览器应该在应用缓存中缓存所有列出的资源。资源可以使用绝对或者相对 URL 来指定(例如 index.html)。

上面例子中的注释 「v1」很有必要存在。只有当清单文件发生变化时,浏览器才会去更新应用缓存。如果你要更改缓存资源(比如说,你使用了一张新的 header.png 图片),你必须同时修改清单文件中的内容,以便让浏览器知道它们需要更新缓存。你可以对清单文件做任何改动,但大家都认同的最佳实践则是修正版本号。

重要:不要在清单文件中指定清单文件本身,否则将无法让浏览器得知清单文件有新版本出现。

缓存清单文件中的段落: CACHE, NETWORK,与 FALLBACK

清单文件可以分为三段: CACHE, NETWORK,与 FALLBACK.

CACHE:
这是缓存文件中记录所属的默认段落。在 CACHE段落标题后(或直接跟在 CACHE MANIFEST 行后)列出的文件会在它们第一次下载完毕后缓存起来。
NETWORK:
在 NETWORK: 段落标题下列出的文件是需要与服务器连接的白名单资源。所有类似资源的请求都会绕过缓存,即使用户处于离线状态。可以使用通配符。
FALLBACK:
FALLBACK: 段指定了一个后备页面,当资源无法访问时,浏览器会使用该页面。该段落的每条记录都列出两个 URI—第一个表示资源,第二个表示后备页面。两个 URI 都必须使用相对路径并且与清单文件同源。可以使用通配符。

CACHE, NETWORK, 和 FALLBACK 段落可以以任意顺序出现在缓存清单文件中,并且每个段落可以在同一清单文件中出现多次。

示例 2: 一个复杂且完整的缓存清单文件

下面是一个更加完整的缓存清单文件,适用于一个虚拟的网站 www.example.com

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

该例子使用了 NETWORK 与 FALLBACK 段落,指明了 network.html 页面必须始终从网络获取,fallback.html 页面应该作为后备资源来提供(例如,当无法与服务器建立连接时)。

缓存清单文件的结构

缓存清单文件必须以 text/cache-manifest MIME 类型来传输。所有通过 MIME 类型传输的文件必须符合本节中定义的适用于应用缓存清单的语法。

缓存清单是 UTF-8 格式的文本文件,有可能包含一个 BOM 字符。新行可能使用换行符(U+000A),回车(U+000D),或回车加换行符来表示。

缓存清单文件的第一行必须包含字符串 CACHE MANIFEST (两个单词间使用一个 U+0020 空白),紧接着是零或多个空白或制表符。本行的其他文本会被忽略。

缓存清单文件的余下内容必须包含零或多个下面的行:

空行
你可以使用包含零或多个空白与制表符的空行。
注释
注释包括零或多个制表符或空白字符,紧接着是一个 # 字符,再然后是零或多个注释文本字符。注释只能在所在行起作用,不能追加到其他行上。这意味着你无法使用片段标识符。
段落标题
段落标题指定了缓存文件即将操作的段落。有三个可选的标题:
段落标题解释
CACHE:切换到缓存清单的显式段落(默认段落)。
NETWORK:切换到缓存清单的在线白名单段落。
FALLBACK:切换到缓存清单的后备资源段落。
段落标题所在的行可以包含空白字符,段落名后的冒号 (:) 不可省略。
段落数据
不同段落的数据行格式有所不同。在默认 (CACHE:) 段落,每行都是一个合法的  URI 或 IRI ,与一个要缓存的资源相关联(本段落内不允许通配符)。每行的 URI 或 IRI 前后允许出现空白字符。在 Fallback 段落内,每行都是一个合法的 URI 或 IRI(与一个资源关联),紧跟着一个后备资源,用于当无法与服务器建立连接时访问。在 Network 段落内,每行都是一个合法的 URI 或 IRI,关联一个需要通过网络获取的资源(本段落内可以使用通配符 *)。
注意:相对 URI 是指相对于缓存清单的 URI,而不是包含清单的文档的 URI。

缓存清单可以在段落内任意切换(每个段落标题可以使用多次),而且段落允许为空。

一个应用缓存中的资源

一个应用缓存至少会包含一个资源,由 URI 指定。所有资源都属于下列类别之一:

主记录
这些资源被加入缓存的原因是:用户浏览的一个上下文中包含一个文档,该文档用 manifest 特性明确指明了它属于该缓存。
显式记录
这些是在应用缓存清单文件中显式列出的资源。
网络记录
这些是在应用缓存清单文件中作为网络记录列出的资源。
后备记录
这些是在应用缓存清单文件中作为后备记录列出的资源。
注意: 资源可以被标记为多个类别,因此可以作为多重记录来分类。例如,一条记录既可以是显式记录,也可以是一条后备记录。

下面来详细介绍资源类别。

主记录

任意在 <html> 元素上包含一个 manifest 特性的 HTML 文件都可以是主记录。例如,我们拥有 HTML 文件 http://www.example.com/entry.html,它看起来是这样的:
<html manifest="example.appcache">
  <h1>Application Cache Example</h1>
</html>

如果 entry.html 没有在 example.appcache 缓存清单文件中列出来,那么访问 entry.html 页面会使得 entry.html 作为一条主记录加入到应用缓存中。

显式记录

显式记录就是在缓存清单文件的 CACHE 段落显式列出的资源

网络记录

缓存清单文件的 NETWORK 段落指定了 web 应用需要在线访问的资源。一个应用缓存中的网络记录本质上来说是一个「在线白名单」—在 NETWORK 段落指定的 URI 会从服务器而不是缓存加载。这使得浏览器的安全模型通过限制用户让其只访问经过验证的资源来避免潜在的安全漏洞。

举例来说,你可以使用网络记录来从服务器而不是缓存中加载并执行脚本或其他代码:

CACHE MANIFEST
NETWORK:
/api

上面列出的缓存清单段落能够保证对 http://www.example.com/api/ 子目录中资源的请求始终通过网络加载,而不会去访问缓存。

注意: 简单的从清单文件中过滤主记录(在 html 元素中拥有 manifest 特性的文件)并不会产生同样的结果,因为主记录会被添加到—后续访问的获取也会从—应用缓存中。

后备记录

当尝试请求资源失败时会使用后备记录。例如,缓存清单文件 http://www.example.com/example.appcache 包含如下内容:

CACHE MANIFEST
FALLBACK:
example/bar/ example.html

任何访问 http://www.example.com/example/bar/ 或它的任意子目录及内容都会使浏览器发出请求,去尝试加载请求的资源。如果尝试失败(可能是由于网络连接失败或服务器问题),浏览器将会加载 example.html。

缓存状态

每个应用缓存都有一个状态,标示着缓存的当前状况。共享同一清单 URI 的缓存拥有相同的缓存状态,可能是其中之一:

UNCACHED(未缓存)
一个特殊的值,用于表明一个应用缓存对象还没有完全初始化。
IDLE(空闲)
应用缓存此时未处于更新过程中。
CHECKING(检查)
清单已经获取完毕并检查更新。
DOWNLOADING(下载中)
下载资源并准备加入到缓存中,这是由于清单变化引起的。
UPDATEREADY(更新就绪)
一个新版本的应用缓存可以使用。有一个对应的事件 updateready,当下载完毕一个更新,并且还未使用 swapCache() 方法激活更新时,该事件触发,而不会是 cached 事件。
OBSOLETE(废弃)
应用缓存现在被废弃。

测试缓存清单的更新

你可以使用 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()。

陷阱

  • 永远不要使用传统 GET 参数(例如 other-cached-page.html?parameterName=value) 来访问缓存文件。这会使浏览器绕过缓存,直接从网络获取。若想链接一个参数需要在 JavaScript 中解析的资源,你可以将参数放到链接的 hash 部分,例如 other-cached-page.html#whatever?parameterName=value。
  • 当应用被缓存后,仅仅更新在 web 页面中使用的资源(文件)还不足以更新被缓存的文件。你需要在浏览器获取和使用更新的文件前,去更新缓存清单文件本身。你可以使用 window.applicationCache.swapCache() 以编程的方式完成上述目的,虽然这无法影响到已经加载完毕的资源。为了保证资源从应用缓存的最新版本中加载,最理想的办法就是刷新页面
  • 通过在 web 服务器上设置 expires header 来使 *.appcache 文件立即过期是个好主意。这避免了将清单文件缓存的风险。例如,在 Apache 中,你可以指定下面的配置项:
    ExpiresByType text/cache-manifest "access plus 0 seconds"

浏览器兼容性

FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari
Basic support4.03.510.010.64.0

注意:Firefox 3.5 之前的版本会忽略缓存清单文件中的 NETWORK 和 FALLBACK 段落。

来自 https://developer.mozilla.org/zh-CN/docs/Web/HTML/Using_the_application_cache

 

普通分类: