应用缓存使用入门指南

简介

离线访问对基于网络的应用而言越来越重要。 是的,如果系统要求您这样做,所有浏览器都可以长时间缓存网页和资源,但浏览器可能会随时将各个项目从缓存中逐出,以便为其他内容腾出空间。HTML5 通过 ApplicationCache 接口。 使用缓存接口为您的应用有以下三个优势:

  1. 离线浏览 - 用户可在离线状态下浏览您的整个网站
  2. 速度 - 资源直接从磁盘中获取,无需访问网络。
  3. 弹性 - 如果您的网站因“维护”而出现故障(比如有人不小心破坏了所有东西),

应用缓存(简称 AppCache)可让开发者指定浏览器应缓存哪些文件 供离线用户查看即使用户按 刷新按钮。

缓存清单文件

缓存清单文件是一个简单的文本文件,列出了浏览器应缓存的资源 进行离线访问

引用清单文件

要为应用程序启用应用程序缓存,请在 文档的 html 标记:

<html manifest="example.appcache">
  ...
</html>

Web 应用的每个页面上都应包含 manifest 属性 您希望缓存的数据如果网页不包含以下元素,则浏览器不会缓存该网页 manifest 属性(除非已明确列出 。也就是说,用户浏览至该网域的任何页面 包含的 manifest 将隐式添加到应用缓存。 因此,您无需在清单中列出每个网页。如果网页指向清单,则无法阻止缓存此网页。

您可以在 Chrome 中访问 about://appcache-internals/,查看由应用缓存控制的网址。在这里,您可以清除缓存并查看条目。Firefox 中有类似的开发者工具

manifest 属性可以指向绝对网址或相对路径, 但绝对网址必须与 Web 应用同源。 清单文件可以使用任何文件扩展名,但需要提供 (见下文)。

<html manifest="http://www.example.com/example.mf">
  ...
</html>

清单文件必须以 MIME 类型 text/cache-manifest 提供。 您可能需要向网络服务器或 .htaccess 配置添加自定义文件类型。

例如,要在 Apache 中提供此 MIME 类型,请将下面这行代码添加到您的配置文件中:

AddType text/cache-manifest .appcache

或者,在 Google App Engine 的 app.yaml 文件中:

- url: /mystaticdir/(.*\.appcache)
  static_files: mystaticdir/\1
  mime_type: text/cache-manifest
  upload: mystaticdir/(.*\.appcache)

此要求在不久前已从规范中被弃用,最新版本的 Chrome、Safari 和 Firefox 已不再要求使用该要求,但是您需要在旧版浏览器和 IE11 中正常使用 MIME 类型。

清单文件的结构

清单是一个单独的文件,您可以通过 HTML 元素的清单属性链接到该文件。简单的清单如下所示:

CACHE MANIFEST
index.html
stylesheet.css
images/logo.png
scripts/main.js
http://cdn.example.com/scripts/main.js

此示例会在指定此清单文件的页面上缓存四个文件。

请注意以下几点:

  • CACHE MANIFEST 字符串位于第一行,且必须提供。
  • 文件可以来自其他网域
  • 某些浏览器对可用存储空间配额量设有限制 应用例如,在 Chrome 中,AppCache 使用 TEMPORARY 的共享池 供其他离线 API 共享的存储空间。如果您要为 Chrome 应用商店编写应用,使用 unlimitedStorage 可以移除该限制。
  • 如果清单本身返回 404 或 410,则缓存会被删除。
  • 如果清单或其中指定的资源无法下载, 整个缓存更新过程都会失败。浏览器会继续使用旧版 应用缓存。

我们来看一个更复杂的示例:

CACHE MANIFEST
# 2010-06-18:v2

# Explicitly cached 'master entries'.
CACHE:
/favicon.ico
index.html
stylesheet.css
images/logo.png
scripts/main.js

# Resources that require the user to be online.
NETWORK:
*

# static.html will be served if main.py is inaccessible
# offline.jpg will be served in place of all images in images/large/
# offline.html will be served in place of all other .html files
FALLBACK:
/main.py /static.html
images/large/ images/offline.jpg

以“#”开头的行是注释行,但也可用于其他用途。 应用的缓存只在其清单文件发生更改时才会更新。 例如,如果您修改图片资源或更改 JavaScript 函数,这些更改不会 必须重新缓存您必须修改清单文件本身,才能通知浏览器刷新缓存文件

避免使用不断更新的时间戳或随机字符串每次都强制更新。更新期间,清单会被检查两次,一次是在启动时检查,另一次是在更新所有缓存文件后。如果清单在更新过程中发生了更改,则浏览器可能从一个版本提取了一些文件,从另一个版本提取了其他文件,因此它不会应用缓存并稍后重试。

虽然缓存会更新,但在网页刷新之前,浏览器不会使用这些文件,因为更新是在从当前版本缓存加载网页之后发生的。

清单可以有三个不同的部分:CACHENETWORKFALLBACK

CACHE:
这是条目的默认部分。列在此标题下(或紧跟在 CACHE MANIFEST 之后)的文件 会在首次下载后被明确缓存 NETWORK:
如果此部分列出的文件不在缓存中,那么它们可能来自网络,否则即使用户在线,也不会使用网络。您可以在此将特定网址列入白名单,也可以直接使用“”,从而允许所有网址。大多数网站需要“”。 FALLBACK:
可选部分,用于指定无法访问资源时的后备网页。第一个 URI 是资源 第二个是在网络请求失败或出错时使用的回退。两个 URI 必须与清单文件来自同一来源。您可以捕获特定网址,也可以捕获网址前缀。“images/large/”会捕获网址中的故障,例如“images/large/whatever/img.jpg”。

以下清单定义了一个“综合”页面 (offline.html), 在离线状态下尝试访问网站的根目录。还声明了所有其他资源(例如远程网站上的资源) 需要连接到互联网。

CACHE MANIFEST
# 2010-06-18:v3

# Explicitly cached entries
index.html
css/style.css

# offline.html will be displayed if the user is offline
FALLBACK:
/ /offline.html

# All other resources (e.g. sites) require the user to be online.
NETWORK:
*

# Additional resources to cache
CACHE:
images/logo1.png
images/logo2.png
images/logo3.png

更新缓存

应用在离线后将保持缓存状态,直到发生以下情况之一:

  1. 用户清除了浏览器在您网站上的数据存储。
  2. 清单文件经过修改。注意:更新清单中列出的文件并不意味着 浏览器就会重新缓存该资源清单文件本身必须更改。

缓存状态

window.applicationCache 对象是以编程方式访问浏览器的应用缓存。 其 status 属性对于检查缓存的当前状态非常有用:

var appCache = window.applicationCache;

switch (appCache.status) {
case appCache.UNCACHED: // UNCACHED == 0
return 'UNCACHED';
break;
case appCache.IDLE: // IDLE == 1
return 'IDLE';
break;
case appCache.CHECKING: // CHECKING == 2
return 'CHECKING';
break;
case appCache.DOWNLOADING: // DOWNLOADING == 3
return 'DOWNLOADING';
break;
case appCache.UPDATEREADY:  // UPDATEREADY == 4
return 'UPDATEREADY';
break;
case appCache.OBSOLETE: // OBSOLETE == 5
return 'OBSOLETE';
break;
default:
return 'UKNOWN CACHE STATUS';
break;
};

如需以编程方式检查清单更新,请先调用 applicationCache.update()。 此操作将尝试更新用户的缓存(需要更改清单文件)。 最后,当 applicationCache.status 处于 UPDATEREADY 状态时, 调用 applicationCache.swapCache() 会将旧缓存替换为新缓存。

var appCache = window.applicationCache;

appCache.update(); // Attempt to update the user's cache.

...

if (appCache.status == window.applicationCache.UPDATEREADY) {
appCache.swapCache();  // The fetch was successful, swap in the new cache.
}

好消息是,您可以自动执行此操作。要将用户更新为 最新版本的网站,请设置监听器以监控 网页加载时 updateready 事件:

// Check if a new cache is available on page load.
window.addEventListener('load', function(e) {

window.applicationCache.addEventListener('updateready', function(e) {
if (window.applicationCache.status == window.applicationCache.UPDATEREADY) {
    // Browser downloaded a new app cache.
    if (confirm('A new version of this site is available. Load it?')) {
    window.location.reload();
    }
} else {
    // Manifest didn't changed. Nothing new to server.
}
}, false);

}, false);

AppCache 事件

如您所料,系统会公开其他事件以监控缓存的状态。 浏览器会针对下载进度、应用缓存更新和错误情况等情况触发事件。 以下代码段为每种缓存事件设置了事件监听器:

function handleCacheEvent(e) {
//...
}

function handleCacheError(e) {
alert('Error: Cache failed to update!');
};

// Fired after the first cache of the manifest.
appCache.addEventListener('cached', handleCacheEvent, false);

// Checking for an update. Always the first event fired in the sequence.
appCache.addEventListener('checking', handleCacheEvent, false);

// An update was found. The browser is fetching resources.
appCache.addEventListener('downloading', handleCacheEvent, false);

// The manifest returns 404 or 410, the download failed,
// or the manifest changed while the download was in progress.
appCache.addEventListener('error', handleCacheError, false);

// Fired after the first download of the manifest.
appCache.addEventListener('noupdate', handleCacheEvent, false);

// Fired if the manifest file returns a 404 or 410.
// This results in the application cache being deleted.
appCache.addEventListener('obsolete', handleCacheEvent, false);

// Fired for each resource listed in the manifest as it is being fetched.
appCache.addEventListener('progress', handleCacheEvent, false);

// Fired when the manifest resources have been newly redownloaded.
appCache.addEventListener('updateready', handleCacheEvent, false);

如果清单文件或其中指定的资源无法下载,则整个 更新失败。如果发生此类故障,浏览器将继续使用旧应用程序缓存。

参考