HTML 应用缓存

简介

HTML5 应用程序缓存 可以对 Web 应用进行缓存,可在没有因特网连接时进行访问;具备离线浏览、快速和减少服务器负载等特点。
通过创建 Cache Manifest 文件,可轻松创建 Web 应用的离线版本。

兼容性

IE10 以及主流浏览器都支持

Cache Manifest 文件

Cache Manifest 文件是 Web 缓存最核心的内容,文件分三个部分,其中 CACHE MANIFEST 是必需要有的;
资源使用 URI 来标识。在缓存清单文件中列出的所有记录必须拥有相同的协议、主机名与端口号(同源)。

文件结构

CACHE MANIFEST //必需不能少
# 2018-03-21 v1.0.0 //版本号注释,建议使用

CACHE://必需,冒号不能省掉

NETWORK: //可选,冒号不能省掉

FALLBACK: //可选,冒号不能省掉
  • CACHE(必需):此节下的文件在首次下载后进行缓存;
  • NETWORK(可选):此节下的文件需要联网且不会被缓存;
  • FALLBACK(可选):此节下的文件规定当页面无法访问时的回退页面(如 404 页面)。

Manifest 文件建议的扩展名是:”.appcache”;
Manifest 文件必须在 web 服务器上配置正确的 MIME-type,即 “text/cache-manifest”,比如在 Apache 中添加 “AddType text/cache-manifest .appcache”。

实例:新建文件名是 txtech.appcache 的缓存文件

CACHE MANIFEST
# 2018-03-21 v1.0.0

CACHE:
/css/theme.css
/images/logo.png
/js/main.js
/htmls/help.html
/htmls/404.html

NETWORK:
/api

FALLBACK:
/htmls/ /offline.html

下面结合应用缓存资源说明 manifest 每部分的功能和作用;

应用缓存资源

一个应用缓存至少会包含一个资源,由 URI 指定,分下面几种类别:

主记录
简单来说是 HTML 文档用 manifest 特性明确指明它可以被缓存;
例如通过页面 manifest 属性指定缓存文件 txtech.appcache 就可以使页面支持离线缓存,如:

<!DOCTYPE HTML>
<html manifest="txtech.appcache">
</html>
或者
<html manifest="/htmls/txtech.appcache">
</html>

缓存清单和 HTML 文档也必须同源

显式记录
应用缓存清单文件中显式列出的资源,相当与缓存清单文件 CACHE 节下面的内容;
例如:

CACHE:
/css/theme.css
/images/logo.png
/js/main.js
/htmls/help.html
/htmls/404.html

CACHE: 下面 theme.css、logo.png、logo.png、help.html 和 404.html 都可以缓存本地;
# 2018-03-21 v1.0.0 是文件注释,更新注释行中的日期和版本号是一种使浏览器重新缓存文件的办法;

网络记录
应用缓存清单文件中作为网络记录列出的资源,相当与缓存清单文件 NETWORK 节下面的内容;
例如:

NETWORK:
/api

表示 /api 目录下的文件需要网络才可以联网;

后备记录
应用缓存清单文件中作为后备记录列出的资源,相当与缓存清单文件 FALLBACK 节下面的内容;
例如:

FALLBACK:
/htmls/ /offline.html

FALLBACK: 表示如果无法加载 /htmls/ 下面所有文件时候,用加载 /offline.html 替代;

资源可以被标记为多个类别,例如,一条记录既可以是显式记录,也可以是一条后备记录。

应用缓存实例

加入缓存清单
有两种方法:

  • 新建缓存文件 txtech.appcache 内容如下,然后让页面 appcache.html 指定它为主记录:
<!DOCTYPE HTML>
<html manifest="txtech.appcache">
</html>
或者
<html manifest="/htmls/txtech.appcache">
</html>
  • txtech.appcache CACHE MANIFEST 下面添加纪录;
CACHE MANIFEST
# 2018-03-22 v1.0.0

CACHE:
/css/style.css
/htmls/404.html

NETWORK:

FALLBACK:

缓存更新
三种条件使浏览器缓存更新:

  • 用户清空浏览器缓存,这种情况使在浏览器清空数据操作;
  • Manifest 文件被修改,这种情况修改了文件的内容,如果文件无变化,则修改上面所说的注释行,那缓存就会更新;包括去掉页面缓存,也必须修改这个文件让浏览器知道应该更新缓存,否则只会从缓存读取内容;
  • 使用代码更新应用缓存,这种情况通过 window.applicationCache 对象相关方法去更新,下面说明;

首先了解缓存状态 window.applicationCache.status

状态 说明
UNCACHED 值是 0,表明一个应用缓存对象还没有完全初始化
IDLE 值是 1,有缓存但此时未处于更新过程中
CHECKING 值是 2,清单已经获取完毕并检查更新
DOWNLOADING 值是 3,下载资源并准备加入到缓存中
UPDATEREADY 值是 4,一个新版本的应用缓存可以使用
OBSOLETE 值是 5,应用缓存现在被废弃

window.applicationCache 对象事件:

事件 说明
oncached() 已经缓存
onchecking() 检查中
ondownloading() 缓存资源正在下载
onnoupdate() 缓存资源没有更新
onupdateready() 缓存资源更新完毕
onprogress() 资源下载进度

window.applicationCache 对象下面相关方法:

方法 说明
update() 尝试更新缓存
swapCache() 交换缓存,用新的缓存覆盖旧的

我们做一完整的例子来演示这些缓存状态,以及更新缓存的代码

<!DOCTYPE html>
<html lang="en" manifest="txtech.appcache">
<head>
    <meta charset="UTF-8">
    <title>应用缓存</title>
    <script type="text/javascript">
        window.applicationCache.oncached = function (e) {
            document.getElementById("cacheEvent").innerText = "缓存成功(oncached)";
            document.getElementById("cacheStatus").innerText = getCacheStatus();
            document.getElementById("progressStatus").innerText = "";
        }
        window.applicationCache.onchecking = function (e) {
            document.getElementById("cacheEvent").innerText = "检查中(onchecking)";
            document.getElementById("cacheStatus").innerText = getCacheStatus();
            document.getElementById("progressStatus").innerText = "";
        }
        window.applicationCache.ondownloading = function (e) {
            document.getElementById("cacheEvent").innerText = "下载中(ondownloading)";
            document.getElementById("cacheStatus").innerText = getCacheStatus();
        }
        window.applicationCache.onnoupdate = function (e) {
            document.getElementById("cacheEvent").innerText = "没有更新内容(onnoupdate)";
            document.getElementById("cacheStatus").innerText = getCacheStatus();
            document.getElementById("progressStatus").innerText = "";
        }
        window.applicationCache.onupdateready = function (e) {
            document.getElementById("cacheEvent").innerText = "更新成功(onupdateready)";
            document.getElementById("cacheStatus").innerText = getCacheStatus();
            window.applicationCache.swapCache();//缓存已经更新,使用新缓存
        }
        window.applicationCache.onprogress = function (e) {
            document.getElementById("progressStatus").innerText = "下载进度(onprogress),已加载资源:" + e.loaded + ",总共资源:" + e.total;
        }
        function getCacheStatus() {
            var status = window.applicationCache.status;
            switch (status) {
                case window.applicationCache.UNCACHED: // UNCACHED == 0
                    return "UNCACHED"
                case window.applicationCache.IDLE: // IDLE == 1
                    return "IDLE"
                case window.applicationCache.CHECKING: // CHECKING == 2
                    return "CHECKING"
                case window.applicationCache.DOWNLOADING: // DOWNLOADING == 3
                    return "DOWNLOADING"
                case window.applicationCache.UPDATEREADY:  // UPDATEREADY == 4
                    return "UPDATEREADY"
                case window.applicationCache.OBSOLETE: // OBSOLETE == 5
                    return "OBSOLETE"
                default:
                    return "UNKNOWN"
                    break;
            }
        }
        function updateCache() {
            window.applicationCache.update(); //尝试更新缓存
        }
    </script>
</head>
<h4>该页面已经使用应用缓存,断开网络再访问试试看</h4>
<label for="cacheEvent">缓存事件:</label>
<span id="cacheEvent"></span><br>
<label for="cacheStatus">缓存状态:</label>
<span id="cacheStatus"></span><br>
<label for="progressStatus">下载状态:</label>
<span id="progressStatus"></span><br>
<input type="button" value="更新缓存" onclick="updateCache()"/>
</body>
</html>

所有效果在这里: 离线缓存演示

  • 断网后可以发现页面还可以访问;
  • 要更新缓存,修改 txtech.appcache 里面的内容或者版本号,然后点更新缓存就可以了;

注意问题

  • 使用传统 GET 参数,例如 appcache.html?parameterName=value 浏览器绕过缓存,直接从网络获取。你可以将参数放到链接的 hash 部分,例如:appcache.html#whatever?parameterName=value,hash 属性是一个可读可写的字符串,该字符串是 URL 的锚部分(从#号开始的部分);

  • 离线资源更新过程某一个文件不能正常下载,整个更新过程将视为失败,浏览器继续全部使用旧缓存;

留下评论

电子邮件地址不会被公开。 必填项已用*标注