注:浏览器以chrome为例
1.MANIFEST文件的加载晚于DOM的加载。所以当浏览器发现有更新并下载后,网页其实已显示了出来,不过还是旧版!想让新内容显现需要reload。
var cache = window.applicationCache;
var count = 0;
if(window.navigator.onLine){
cache.addEventListener('noupdate', function(e){
console.log("没有更新可用");
}, false);
cache.addEventListener('downloading', function(e){
console.log("准备下载更新");
}, false);
cache.addEventListener('progress', function(e){
count++;
console.log(count + "个文件下载完成");
}, false);
cache.addEventListener('updateready', function(e){
console.log("下载完毕");
cache.swapCache();
document.location.reload();
}, false);
}
else{
console.log("无网络");
}
2.当浏览器加载了MANIFEST文件发现有更新,开始下载文件里列举的资源。然而浏览器先访问了自己的browser cache,且有可能把browser cache中的文件提交给了AppCache,来了个"以旧换旧"。1中的事件能正常触发,只是网页内容没有更改...解决办法是禁止缓冲。
以tomcat为例,设一个过滤器:
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletResponse rp = (HttpServletResponse) response;
rp.setHeader("Cache-Control", "no-cache");
rp.setHeader("Pragma", "no-cache");
rp.setDateHeader("Expires", -1);
chain.doFilter(request, response);
}
其实文件还是会出现到浏览器缓冲列表里,但是被加上了"no-cache"标志(可以用chrome cache view查看)。这样更新app cache时浏览器就会略过browser cache从服务器下载文件。
这两个坑是不是非常的"坑"?感觉简直是荒唐!不合乎逻辑嘛!我想原因有二:
1.html5并不是一项全新技术,它是在传统html基础上新增的一些东西如application cache。在保持兼容前提下,性能可能无法做到最优化。
2.最重要的,大型软件工程(尤其是开源工程),都是分"层/块"设计制作的。设计者只需实现自己这一层/块的接口就行。比如说浏览器从browser cache里给app cache找文件这种荒唐事,browser cache其实应该叫做"http cache",它是网络传输中的一层。内核文件/数据处理代码发现MANIFEST文件更新了,于是把下载请求提交给网络层,至于网络层如何运作就管不了了。而网络层接收到文件请求后,首先会查看缓冲,缓冲里的不可用再请求服务器。至于这个文件是用来干嘛的,它就不管了。所以才会导至第二个坑。
参考资料:
注:
1.在第一篇参考文章中,作者通过添加"Vary: Accept-Encoding" 返回头的方法避免第二个坑。但经我试验不成功。可能是环境不相同?而且"Vary: Accept-Encoding"确实已过时了。
2.如果想清除浏览器application cache,方法是删除服务器上的MANIFEST文件。