HTML5的新增了很多浏览器本地存储的技术,Application Cache(简称 AppCache)使得基于web的应用程序可以离线运行,似乎是为支持 Web App 离线使用而开发的缓存机制。它的缓存机制类似于浏览器的缓存(Cache-Control 和 Last-Modified)机制,都是以文件为单位进行缓存,且文件有一定更新机制。但 AppCache 是对浏览器缓存机制的补充,不是替代。

离线存储的作用

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

如何应用

通过在站点根目录维护一个manifest文件,在需要缓存的html页面中引入这个文件。

manifest 文件是简单的文本文件,它告知浏览器被缓存的内容(以及不缓存的内容),支持manifest的浏览器,会将按照manifest文件的规则,将文件保存在本地,从而在没有网络链接的情况下,也能访问页面。

实践示例

manifest文件结构

假如我们在根目录下新建一个名为manifest.appcache的文件(该文件名和后缀名后可以自定义),配置内容如下:

CACHE MANIFEST
# version 1.0.0  以 # 声明注释,浏览器根据manifest文件变化来检测是否需要重新加载新文件。
# 注释:需要缓存的文件,无论在线与否,均从缓存里读取
/images/cached.png
/css/cached.css
/js/cached.js

# 需要特殊声明的缓存文件,也可以都在这里声明
CACHE:
/css/otherCached.css
/js/otherCached.js

# 注释:不缓存的文件,无论缓存中存在与否,均从新获取
NETWORK:
*

# 注释:获取不到资源时的备选路径,如index.html访问失败,则返回404页面
FALLBACK:
index.html 404.html
  • 1、CACHE MANIFEST — 文件开头第一行必须声明 CACHE MANIFEST 字段标识,然后紧接着声明需要缓存的文件路径,作用是标识出哪些文件需要缓存,可以是相对路径也可以是绝对路径;
  • 2、# #号开头的是注释,一般会在第二行写个版本号,用来在缓存的文件更新时,更改manifest的作用,可以是版本号,时间戳或者md5码等等;
  • 3、CACHE — 我们也可以在CACHE下面声明需要缓存的资源路径;
  • 4、NETWORK可选,这一部分是要直接读取的文件,可以使用通配符 *
  • 5、FALLBACK可选,指定了一个后备页面,当资源无法访问时,浏览器会使用该页面。

HTML引入示例

在文档的 <html> 标签中添加 manifest 属性,将manifest.appcache文件引入:

<!DOCTYPE HTML>
<html manifest="manifest.appcache">
<link rel="stylesheet" href="/css/cached.css"/>
<body>
	<p><img src="/images/cached.png"/></p>
  	<script src="/js/cached.js"></script>
</body>
</html>

这样浏览器在读取HTML页面时会将manifest.appcache中声明的资源下载并进行离线存储,下次请求直接使用离线存储中的资源,HTTP请求表现为:200 (from disk cache)

配置服务器

一般情况下,manifest 文件需要在web 服务器上配置正确的 MIME-type,即 “text/cache-manifest”,才能正常的被浏览器正常请求。

Nginx

打开Nginx配置文件目录下的mine.types文件,添加如下配置:

types {
    text/cache.manifest              manifest;
}

Apache

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

更新缓存资源

浏览器离线存储缓存机制示意图:

img

  • 用户初次访问网站,浏览器读取到<html>标签中manifest属性声明的manifest.appcache文件,根据manifest文件的内容下载相应的资源并进行离线存储。

    以Chrome浏览器为例,会在Application - Application Cache中展现当前站点已缓存的资源。

    如图:

    Markdown

  • 资源已经离线存储后,用户再次访问时,浏览器就会使用离线的资源加载页面,然后浏览器会对比新的manifest文件与旧的manifest文件,如果文件没有发生改变,就不做任何操作,如果文件改变了,那么就会重新下载文件中的资源并进行离线存储。

    需要注意的是浏览器下载新的更新资源后并不会立即使用,需要刷新页面才有效果,我们可以利用JavaScript提供的接口监听浏览器是否更新了资源,如果更新了就通过window.location.reload刷新页面或通知用户有更新。

  • 离线的情况下,浏览器就直接使用离线存储的资源。

JavaScript监听更新

监听示例:

var appCache = window.applicationCache;
    appCache.onupdateready = function(e) {
    appCache.swapCache();
    window.location.reload();
};

关于window.applicationCache对象的更多接口信息可参考以下表格内容:

applicationCache对象

该对象是window对象的直接子对象window.applicationCache

基类:DOMApplicationCache

事件列表

事件 接口 触发条件 后续事件
checking Event 用户代理检查更新或者在第一次尝试下载manifest文件的时候,本事件往往是事件队列中第一个被触发的 noupdate, downloading, obsolete, error
noupdate Event 检测出manifest文件没有更新
downloading Event 用户代理发现更新并且正在取资源,或者第一次下载manifest文件列表中列举的资源 progress, error, cached, updateready
progress ProgressEvent 用户代理正在下载资源manifest文件中的需要缓存的资源 progress, error, cached, updateready
cached Event manifest中列举的资源已经下载完成,并且已经缓存
updateready Event manifest中列举的文件已经重新下载并更新成功,接下来js可以使用swapCache()方法更新到应用程序中
obsolete Event manifest的请求出现404或者410错误,应用程序缓存被取消

另外还有一个error事件,触发条件如下:

  • manifest的请求出现404或者410错误,更新缓存的请求失败;
  • 无manifest文件没有改变,但是页面引用的manifest 文件没有被正确地下载;
  • 在取manifest列举的资源的过程中发生致命的错误;
  • 在更新过程中manifest文件发生变化用户代理会尝试立即再次获取文件。

属性

status属性返回缓存的状态

可选值 匹配常量 描述
0 appCache.UNCACHED 未缓存
1 appCache.IDLE 闲置
2 appCache.CHECKING 检查中
3 appCache.DOWNLOADING 下载中
4 appCache.UPDATEREADY 已更新
5 appCache.OBSOLETE 失效

方法

方法名 描述
update() 发起应用程序缓存下载进程
abort() 取消正在进行的缓存下载
swapcache() 切换成本地最新的缓存环境

Webpack中配置自动化

在使用webpack自动化构建的项目中,我们可以利用appcache-webpack-plugin这个插件轻松生成manifest文件,并将打包的资源路径更新到manifest文件中,配置如下:

const AppCachePlugin = require('appcache-webpack-plugin');

plugins: [
 	new AppCachePlugin({
        cache: ['otherAsset.png'],
        network: ['*'],  // 除了声明的缓存资源其他都通过网络访问
        fallback: ['index.html', 'error.html'],
        settings: ['prefer-online'],
        exclude: ['file.txt', /.*\.html$/],  // Exclude file.txt and all .html files
        output: '/manifest.appcache'
   })
]

注意事项

  • 已经被缓存的文件,无论在线与否,浏览器均从缓存里读取。
  • 如果服务器更新了资源,一定要更新manifest文件,并且缓存的文件名也需要做相应的变化,这样新的资源才会被浏览器重新下载并更新到离线存储。如果没有更新manifest文件,浏览器将不会下载新的资源,继续使用离线存储中旧的资源。
  • 不要对manifest文件设置缓存。因为有可能即使你对manifest文件进行了更新,但是由于HTTP的缓存规则告诉浏览器本地缓存manifest文件还未过期,并不会返回新的manifest文件。
  • 浏览器在下载manifest中的文件时,会一次性下载所有的文件,一旦因为某些原因某一个资源下载失败,会导致所有的资源更新失败,浏览器继续适应旧的资源。
  • <html> 属性中的manifest文件必须与该HTML页面同源。
  • FALLBACK中声明的资源必须和manifest文件同源。
  • 站点中的其他页面即使没有设置manifest属性,请求的资源如果在缓存中也从缓存中访问。
  • 站点离线存储的容量限制是5M。
相关标签
qrcode-pay