Html5-ApplicationCache

前段时间做了一个音乐电台的页面。美女同事录了一段10M+的MP3文件,需要做成一个图文并茂+电台音乐背景的H5页面,当时直接放根目录下用<audio>播放,页面上线后美女的图文介绍+治愈系声音果然引来一大票拥趸。有些用户听一遍还不过瘾,反复进入页面收听,关键是有人用的不是wifi,而是3G或4G的流量,特别是4G的,速度快,流量走得更快。因为<audio>的文件一旦开始播放就算中途暂停它也会把文件加载完,而且页面不会自动缓存。然后这些用户就收到了流量告急的通知,然后我就收到了投诉。

当时第一反应就是怎么让浏览器把mp3文件缓存下来(现在想想可以上传到视频网站上用直播流,当时真是考虑不周到啊),于是有了对ApplicationCache的研究。

关于ApplicationCache,《HTML5与CSS3权威指南》中的原话是:为了让Web应用程序在离线状态时候也能正常工作,就必须要把所有构成Web应用程序的资源,诸如HTML文件、css文件、JaveScript脚本文件等放在本地缓存中,当服务器没有和Internet建立连接的时候,也可以利用本地缓存中的资源文件来正常运行Web应用程序。

ApplicationCache与浏览器网页缓存的区别与其优势

区别:本地缓存为整个web提供服务,浏览器缓存只缓存单个页面;本地缓存可以指定页面、文件进行缓存,也可以通过程序控制更新,而我们无法知道浏览器缓存对哪些页面哪些文件进行了缓存,也不知道这些页面文件什么时候会进行更新(除了一直F5或清除浏览器缓存)。

如何实现

首先是配置服务器。离线存储是通过manifest文件来管理的,需要服务器端的支持,不同的服务器开启支持的方式也是不同的。

对于Tomcat需要修改 /conf/web.xml文件,添加如下MIMEType配置:

<mime-mapping>
    <extension>manifest</extension>
    <mime-type>text/cache-manifest</mime-type>
</mime-mapping>

<extension>manifest</extension>中内容必须和manifest文件后缀名一致。

对于Apache可以有两种方式:

  1. 在根目录的.htaccess 文件中的mime_module中添加。适用于仅针对单个站点进行设置。
<IfModule mime_module>
    AddType text/cache-manifest .manifest
</IfModule>

2 在httpd.conf文件中添加配置。适用于服务器全局,也可以对单个主机进行设置。

<IfModule mime_module>
AddType text/cache-manifest .manifest
</IfModule>

注:manifest文件可以自定义后缀名,一般用manifest或appcache,可以根据喜好自行选择。

然后,创建 缓存列表文件filename.manifest:

其中第一行的 CACHE MANIFEST 标识是文件声明,告知浏览器本文件的作用。

CACHE / NETWORK / FACKBACK 三个关键字用于不同功能:

  • CACHE 指定需要被缓存的文件
  • NETWORK 指定不需要被缓存的文件
  • FALLBACK 每行指定两个资源文件,第一个为在线时使用的文件,第二个为离线时使用的文件

文件编码最好使用utf-8;

行开头“#”是注释;

CACHE MANIFEST
#版本编号,可以用来控制浏览器更新
#VERSION 1.3

# 需要缓存的文件
CACHE:
#绝对路径
http://sitename/filename
#相对路径
img/bg.jpg
js/jquery.min.js
css/main.css

#不需要缓存的文件
NETWORK:
#*表示出CACHE指定文件外的其他文件,也可以指定具体文件
*

#替代文件
FAILBACK:
file1.html file2.html


    最后,给 <html> 标签加 manifest 属性,如下:

<!DOCTYPE html>
<html lang="en" manifest='test.manifest'>
	<head></head>
	<body></body>
</html>

至此,Application Cache设置就完成啦,可以测试一下,缓存后速度刚刚的。可以用chrome的开发者工具 >Resource>Application Cache 可以查看已缓存的文件。

如何更新缓存

用了缓存一定会涉及到更新的问题,这也是Application Cache最蛋疼的地方。

按照标准,应用在离线后将保持缓存状态,除非发生以下某种情况:

  1. 用户清除了浏览器缓存或脱机数据。
  2. 清单文件经过修改。请注意:更新清单中列出的某个文件并不意味着浏览器会重新缓存该资源。清单文件本身必须进行更改,一般通过更新版本号来实现。


    window.applicationCache 对象可以用来查看本地缓存的当前状态,也可以用来手动更新本地缓存。window.applicationCache 对象有几个不同的状态,分别触发相对应的事件:

事件名称 接口 何时触发 下一个事件
checking Event 当user agent检查更新时,或第一次下载manifest清单时,它往往会第一个被触发 noupdate,downloading,obsolete,error
noupdate Event Manifest清单没有变化 这将是最后一个被触发的事件
downloading Event User agent发现manifest清单有更新,或第一次下载清单上列出的资源 progress,error,cached,updateready
progress ProgressEvent User agent正在下载manifest清单上列出的资源 progress,error,cached,updateready
cached Event Manifest清单上列出的资源都已被下载,且已被应用程序所缓存 这将是最后一个被触发的事件
updateready Event Manifest清单上列出的资源都已被重新下载,script脚本可以通过swapCache()来切换到新的缓存 这将是最后一个被触发的事件
obsolete Event Manifest清单文件返回404或410页面时,应用程序将删除缓存 这将是最后一个被触发的事件
error Event

Manifest没有变化,但页面所引用的manifest可能下载失败了

遍历manifest清单上列出的资源时发生了致命错误

Manifest在应用程序进行更新时发生了改变

这将是最后一个被触发的事件

User agent将在瞬间再次尝试遍历该清单文件

详见W3C Spec:http://www.w3.org/TR/2012/WD-html5-20120329/offline.html#offline

可以从下图理解ApplicationCache的工作原理和事件触发的顺序

不过ApplicationCache的更新机制有个明显的硬伤就是:一般情况下缓存有了更新之后,用户需要刷新两次页面才可以看到更新后的页面。因为第一次刷新浏览器会先使用旧的缓存文件再去检查更新,更新之后也不会立刻体现在页面上,需要下一次刷新页面才会使用新的资源文件。

以下代码可以优化这一过程的体验,但不能根本解决:

setInterval(function(){
	//通知浏览器检测是否有更新,该方法会在页面载入时自动触发一次
	applicationCache.update();
},10000);
applicationCache.addEventListener("updateready",function(){
	if(confirm("本地缓存已被更新,是否刷新页面来获取最新版本?")){
		//该方法也是在页面载入时自动触发一次,这里只不过将它提前执行
		//如果缓存中有大文件的话这个方法还是会耗费一定的时间
		applicationCache.swapCache();
		location.reload();
	}
})

还有一些需要注意的事项

1. 如果manifest文件,或者内部列举的某一个文件不能正常下载,整个更新过程将视为失败,触发error事件,浏览器继续全部使用老的缓存

2. 引用manifest的html必须与manifest文件同源,在同一个域下

3. 在manifest中使用的相对路径,相对参照物为manifest文件

4. 系统会自动缓存引用清单文件的 HTML 文件,这意味着对html的更新也要刷新两次

5. manifest文件中CACHE则与NETWORK,FALLBACK的位置顺序没有关系,如果是隐式声明需要在最前面

6. FALLBACK中的资源必须和manifest文件同源

7. 当一个资源被缓存后,该浏览器直接请求这个绝对路径也会访问缓存中的资源。

8. 站点中的其他页面即使没有设置manifest属性,请求的资源如果在缓存中也从缓存中访问

9. 当manifest文件发生改变时,资源请求本身也会触发更新

10.在manifest文件下指定缓存的文件,就算页面上没有用到,只要在服务器中存在,浏览器就会去获取


到这里,Application Cache的机制基本上就讲完了,看起来也不难。但是,如果你认为这样就可以高枕无忧地使用Application Cache的话那就错了,因为一些浏览器从来都不按套路出牌。

我测试了两个PC浏览器,分别是Chrome和FireFox,结果都不尽人意,其中:

FireFox不支持php文件引用manifest进行本地缓存,所以index.php引用manifest跟没引用一样。而在index.html中的表现又太过了,怎么过了呢?就是manifest文件更新后,执行上面的优化代码检测不到更新,好像是连.manifest文件都缓存下来的感觉,所以缓存后没办法更新资源文件,只能手动清除浏览器缓存和脱机数据。

Chrome下面呢?表现得非常好,但也仅仅是表现。怎么说呢?它php和html文件都支持引用manifest进行缓存,而且执行上面的优化代码,服务器上的manifest文件更新后不用刷新都会提示你”缓存有更新,要不要刷新页面?“但是刷新页面后却依旧是旧数据,对,仅仅是表现好,没有实际行动,还是要通过手动清除缓存来更新。

也有好消息,我测试了移动端的QQ,UC和微信浏览器,表现都让人挺满意,都按套路出牌。

总结

Application Cache的应用目前并没有很普及,除了它自己本身的更新机制的硬伤外(难道用户每次进来都刷刷两次刷新看看有没有更新先吗),还有就是浏览器支持的差异也很大。所以我的建议是如果要使用Application Cache,一定要充分考虑到终端浏览器的种类和需要缓存的文件,并进行充分的测试,就算是这样,也不能太依赖这个东西,我认为目前来看Application Cache只能算是一种优化方法,不是一个成熟的解决方案。

注:以上图文部分来自网络,部分原创,如侵犯到您的权益,请及时通知我。


相关文章

  • 没有相关文章!
0 吐槽
欢迎吐槽丢砖~点赞也行