首页 HTML5 Dive Into HTML5:离线Web程序

Dive Into HTML5:离线Web程序

0 1.5K

什么是离线 web 程序?咋一看起来,它很像一个矛盾。web 页面就是你下载下来之后渲染的。下载暗示着必须联网。那么当你离线的时候怎么下载呢?显然,你不能。但是你可以连线的时候下载好。这就是 HTML5 离线程序的工作原理。

最简单的一种离线web程序包括一系列 URL—— HTML、CSS、JavaScript、图像,以及其他类型的资源。在线 web 程序的主页有个文件指定这个列表,称为 manifest 清单文件。这仅仅是一个放置在 web 服务器的文本文件。实现了 HTML5 离线程序功能的浏览器从 manifest 文件读取 URL 列表,下载所有资源,将它们缓存到本地,并且能够在它们被修改的时候自动更新这些缓存文件。当你离线访问 web 程序时,浏览器自动转换到本地缓存的版本。

现在,大部分工作都交给你了,web 开发者。DOM 中有一个标记可以告诉你现在是在线还是离线。当你的离线状态发生改变的时候(这一分钟你离线,下一分钟你就在线了,或者相反的情况下),浏览器会发出一些事件。这些事件还是很多的。如果应用程序需要创建数据或者保存状态,那么,在离线状态下是否需要将数据存储到本地,然后在连接到服务器时自动与远程服务器同步,就取决于你的实现了。换句话说,HTML5 可以让你的 web 程序离线运行,而你的程序离线的时候到底如何运行则取决于你。

IEFirefoxSafariChromeOperaiPhoneAndroid
-3.5+4.0+5.0+10.6+2.1+2.0+

缓存清单文件

离线 web 程序需要一个缓存的清单文件。什么是清单文件?它是你的 web 程序所需要的所有资源的一个列表,在你离线访问程序的时候可能会用到这些资源。为了加快下载速度、缓存这些资源,你需要将这些资源在清单文件中指明。我们需要在<html>中使用 manifest 属性。

<!DOCTYPE HTML>
<html manifest="/cache.manifest">
<body>
...
</body>
</html>

缓存清单文件可以在 web 服务器的任何位置,但是其内容类型必须是 text/cache-manifest。如果你的服务器是基于 Apache 的,那么可以在 web 站点根目录的 .htaccess 文件中使用 AddType 指令添加:

AddType text/cache-manifest .manifest

然后确保清单文件的文件名以 .manifest 结束。如果你使用不同的 web 服务器或者 Apache 的不同配置,请自行查阅服务器的文档,应该是在管理 Content-Type 头这么一节中。

FAQ

Q: 我的 web 程序有好几页,那么我需要在每一页都加入这个 manifest 属性吗?还是仅仅在首页加入?

A: 你的程序的每一页都需要加入 manifest 属性,用以指出整个程序的清单。

好了,现在你的每一个 HTML 页面都指定了一个缓存清单文件,并且该文件也有了合适的 Content-Type 头。那么,这个文件我们该如何编写呢?这才是最有趣的地方。

缓存清单文件第一行是这样的:

CACHE MANIFEST

在那之后,所有的清单文件都被分为三部分:“显式”部分(explicit)、“回调”部分(fallback)和“在线白名单”(online whitelist)。每一部分都有占据单独一行的头。如果清单文件没有任何头,则所有资源都默认是在 explicit 部分。” 提醒一点,不要纠结于这些名词,以免你会头疼。

下面是一个合法的清单文件。它列出了三个资源:一个 CSS 文件,一个 JavaScript 文件和一个 JPEG 图片。

CACHE MANIFEST
/clock.css
/clock.js
/clock-face.jpg

这个清单文件没有分块的头信息,因此所有列出的资源都属于 explicit 部分。explicit 部分的资源将被下载下来,缓存到本地,并且在程序离线的时候使用。因此,在加载这个清单文件之后,浏览器就会将 clock.css、clock.js 和 clock-face.jpg 从web服务器根目录下载下来。当你的网络断掉后,重新刷新页面,这些资源将继续可以使用。

FAQ

Q: 我需要在缓存清单文件中列出 HTML 页面吗?

A: 是,也不是。如果你的整个 web 应用程序仅有一个页面,只要确保这个页面使用了 manifest 属性指定了清单文件即可。当你浏览一个指定了 manifest 属性的 HTML 页面时,这个页面将自动作为 web 程序的一部分,所以你无需在清单文件中列出来。但是,如果你的程序有多个页面,你需要在清单文件中列出所有 HTML 页面,否则浏览器不知道哪些页面应该被下载并且缓存下来。

Network 块

下面是一个比较复杂的例子。假设你想让你的时钟程序追踪访问者,使用<img src>指定的一段 tracking.cgi 脚本。将这个资源缓存下来显然没什么用处,因为本地使用的话并不能起到追踪的作用。所以,这个资源不应该被缓存起来,也不能离线使用。下面我们告诉你该怎么做:

CACHE MANIFEST
NETWORK:
/tracking.cgi
CACHE:
/clock.css
/clock.js
/clock-face.jpg

这个缓存清单文件包含有块的声明。NETWORK 这行标志着 online whitelist 块的开始。这个块中列出的资源不应该被缓存,也不能够离线使用。(试图离线加载会引发一个错误。)CACHE 这行标志着 explicit 块的开始。这个清单的剩下部分同前面是一样的。这三个资源都将被缓存,并且可以用于离线使用。

Fallback 块

清单文件还有一种块类型:fallback 块。在 fallback 中,你可以定义那些不能被缓存,或者没有缓存成功的资源的替代资源。HTML5 标准提供了一个例子:

CACHE MANIFEST
FALLBACK:
/ /offline.html
NETWORK:
*

这是在做什么?首先,想象一个拥有几百万页面的网站,例如 Wikipedia。你不可能将整个站点都下载下来,即使你想这么干。不过,你可以让某一部分可以离线使用。但你怎么指定哪些页面被缓存呢?看看这么做怎么样:在一个假想的 Wikipedia 站点上,每一个你浏览过的页面都可以被下载并且被缓存。这将包含你浏览过的每一个内容页面,每一个讨论页面,每一个编辑页面。

这就是这个清单文件做的事。假设 Wikipedia 上每一个 HTML 页面(内容页、讨论页、编辑页和历史页面)都指定了这个清单文件。当你访问这个清单文件指定的任何页面的时候,浏览器会说,“这个页面时离线 web 程序的一部分,这是我曾经下载过的吗?”如果浏览器从来没有下载过这个清单文件,它将创建一个新的离线 “appcache”(也就是 application cache),将清单文件指定的所有资源都下载下来,但后将当前页面加入到 appcache。如果浏览器已经下载过这个清单文件,它仅仅将当前页面加入已有的 appcache。不管哪种方法,你访问的页面都被添加到了 appcache。这是十分重要的一点。这意味着你可以有一个能够“迟缓”添加页面的离线 web 应用程序。你不需要将所有单独的 HTML 页面都添加到清单文件中。

下面看看 fallback 块。清单文件中的 fallback 块只有一行。这一行的第一部分(空格之前的部分)不是一个 URL。它只是一个 URL 模式。一个单独的字符 / 可以匹配你的站点的任何页面,不仅仅是首页。当你离线访问一个页面的时候,浏览器将从 appcache 中查找、如果找到(这是因为你曾经在线访问过它,该页面被隐式添加到了 appcache 中),则显示这个页面的缓存;如果没有,浏览器也不会显示错误,而是显示 /offline.html 页面,这是由 fallback 块的这行的第二部分指定的。

最后,我们再看看 network 块。network 块也只有一行,这一行仅有一个字符 *。这个字符在 network 块有特殊的含义。它被称为“在线白名单通配符 online whitelist wildcard flag”。它说明,只要你有 web 连接,所有不在 appcache 中的资源都应该从原始 web 地址下载。这对于一个“开放式结尾”的 web 应用程序尤其重要。它意味着,当你浏览这个假想的能够离线访问的 Wikipedia 的时候,浏览器可以像其他网站一样获取图片、视频或者其它嵌入资源,甚至是不同域名下的。(这在大型网站中很常见,甚至它们根本不是离线 web 程序的一部分。HTML 页面可以在本地缓存,而图片和视频则需要通过另外一个域名的 CDN 获取。)如果没有通配符,我们的离线 Wikipedia 在在线浏览的时候就会显得很奇怪——不能加载任何不在同一服务器的图片或者视频!

这个例子是完备的吗?不是。Wikipedia 不仅仅是 HTML 文件。它还在每一个 HTML 页面使用了 CSS、JavaScript 和各种图片。这些所有资源都需要显示地被列在清单文件的 CACHE 块中,以便让这些页面能够正确地离线显示。但是,fallback 块则指出一个“开放式结尾”的离线 web 程序,能够让没有在清单文件中列出的资源正确使用。

发表评论

关于我

devbean

devbean

豆子,生于山东,定居南京。毕业于山东大学软件工程专业。软件工程师,主要关注于 Qt、Angular 等界面技术。

主题 Salodad 由 PenciDesign 提供 | 静态文件存储由又拍云存储提供 | 苏ICP备13027999号-2