HTML5离线应用无法更新的定位与解决

时间:2022-11-09 09:59:56

一、些许前提

最近在制作一个Web应用, 其中用到了HTML5的离线应用功能(offline application), 离线应用的概念就不再阐述, 可以查看这两篇文章:

http://www.ibm.com/developerworks/cn/web/1011_guozb_html5off/

http://www.mhtml5.com/2011/02/583.html

这里主要讨论它的更新问题. 首先浏览器是有两部分cache的, browser cache 和app cache, browser cache就是常说的浏览器缓存, app cache是离线应用的缓存. 他们各自的更新机制如下:

HTML5离线应用无法更新的定位与解决

Browser cache

HTML5离线应用无法更新的定位与解决

App cache

其中browser cache的机制大家都很清楚了, 其中离线应用的更新是: 除了第一次访问是直接拉取server的, 然后后台更新app cache之外, 其余的情况都是直接访问app cache. 因此, 要如果离线应用的代码更新了, 只有下次打开或者刷新才会生效.

二、找出凶手

OK, 铺垫完毕. 我的应用主要在webkit内核的浏览器使用的, 为了方便起见, 下面的文字都是在chrome的环境下产生的.

在测试机测试离线功能时, 我们发现, 如果更改了js文件且更新了manifest, 刷新两次(嗯, 你没看错,是两次, 第一次于后台更新app cache, 第二次应用新cache)就会应用上新的代码. 但是, 发布到正式环境之后, 就不能更新了, 把F5按烂了, 也没什么变化. 当然这是删除掉app cache是没问题的, 但是我们没办法要求用户这样做.

通过抓包发现, 无论哪个环境, manifest更新了, 浏览器端都能抓取新的, 在chrome的控制台也能看到更新app cache的log, 因此不是manifest本身被缓存了的原因. 但是在正式环境里面, 拉取了新的manifest之后, 就没有任何更新的请求出去, 太诡异了.

继续对比http的响应头, 发现了不同之处, 如下:

测试环境 正式环境

HTTP/1.1 200 OK

Date: Thu, 05 Jan 2012 05:56:38 GMT

Server: NWS_HY_P91

Last-Modified: Thu, 05 Jan 2012 04:29:52 GMT

Expires: Thu, 05 Jan 2012 05:56:38 GMT

Connection: close

Content-Type: application/javascript

Vary: Accept-Encoding

HTTP/1.1 200 OK

Date: Thu, 05 Jan 2012 05:56:38 GMT

Server: nginx

Last-Modified: Thu, 05 Jan 2012 04:29:52 GMT

Expires: Thu, 05 Jan 2012 05:56:38 GMT

Connection: keep-alive

Content-Type: application/javascript

Cache-Control: max-age=10368000

可以看到, 两个环境里面有3个不同, connection, vary, cache-control. 第一眼望去, 感觉就可能是cache-control的问题. 于是用fildder把响应卡住, 把max-age改成0, 结果呢, 它正常更新了! 因此猜测app cache的更新应该是先去browser cache找, 找到了该文件, 并且没过期, 就不再访问server了, 因此抓包也看不到任何请求. 它的流程应该是这样的:

HTML5离线应用无法更新的定位与解决

App cache 2

于是我本地搭了一个apache验证, 把js的max-age设置为30秒, 果然在30秒内, 无论怎么修改manifest和js, 都不会有对js的新请求, 它一直在向browser cache拉取, 而30秒之后, 就能去server拉去新的js了.

三、谁是真凶?

理论上这件事就应该到此为止了, 只要把正式环境的cdn都去掉cache-control就大功告成啦. 但是,去掉cache-control将大大浪费公司的带宽! 而且deewii童鞋发现, 有一台放置vm(应用用到的一个接口层, 是一个页面)的机器, 也设置了cache-control, 但是却能正常更新, 这下又变得扑朔迷离了.

刚才我们对比响应头发现了三个不同, 继续看connection这东西, keep-alive是用来保持长连接的, 莫非是它的影响? 但是抓了几个包, 却发现vm所在机器返回的响应头里面是Connection: keep-alive, 因此排除了这个影响.

最后只能把希望放在Vary: Accept-Encoding 里面了, 还是刚刚搭apache, 加上max-age=10368000, 加上keep-alive, 加上Vary: Accept-Encoding, 修改manifest, 刷新… 天, 竟然发起更新请求了! 原来你(Accept-Encoding)才是真正的凶手! 有没有可能是本地才会这样呢, 继续用fiddler卡住正式环境的响应, 加上Vary: Accept-Encoding, 果然刷新之后也能正常更新了.

虽然找到原因, 但是本人对这个Accept-Encoding不是很了解, 查了些资料(参考这里:http://www.falconhan.com/webanalytics/vary-accept-encoding-header.htm ), 猜测Accept-Encoding是用来告诉浏览器只缓存它自己声明的类型(在发起的http请求头里面指定, 例如: Accept-Encoding: gzip,deflate,sdch)的文件, 而存在于browser cache里面的内容则是浏览器解压后的, 因此app cache去browser cache更新的时候发现格式不对, 就抛弃掉, 继续去server请求. 不知道想的对不对, 欢迎拍砖指正.

四、写在后面

花了一个晚上+一个上午, 总算把这个无法更新的问题解决了. 虽然最后得到的结论很简单, 只要在服务器配个返回头就行了, 但是找问题的时候相当痛苦. 归根到底还是对http协议不够了解, 学艺不精还得继续努力.

PS: 在用firefox测试的时候, 发现它只有第一次打开(或者删掉离线数据之后)的时候会去请求manifest和其他离线资源, 之后它竟然完全不访问manifest, 导致没办法更新, 网上也没找到什么好资料(网上也有遇到相同状况的童鞋: http://hi.baidu.com/erik168/blog/item/aadff9547720d8013b293559.html ), 不知道有没有童鞋了解的.

参考资料

Offline Application

http://www.ibm.com/developerworks/cn/web/1011_guozb_html5off/

http://www.mhtml5.com/2011/02/583.html

http://www.mhtml5.com/resources/html5-js-api-%E6%95%99%E7%A8%8B%EF%BC%88%E5%9B%9B%EF%BC%89-%E7%A6%BB%E7%BA%BF%E5%BA%94%E7%94%A8

Vary: Accept-Encoding

http://www.falconhan.com/webanalytics/vary-accept-encoding-header.htm

http://hi.baidu.com/%B9%E3%D6%DD_it%C4%D0/blog/item/c2dd76c96d1eb4009c163d2a.html

http://mark.koli.ch/2010/09/understanding-the-http-vary-header-and-caching-proxies-squid-etc.html

Firefox的ApplicationCache

http://hi.baidu.com/erik168/blog/item/aadff9547720d8013b293559.html

HTML5离线应用无法更新的定位与解决的更多相关文章

  1. HTML5离线缓存(Application Cache)

    HTML5离线缓存又名Application Cache,是从浏览器的缓存中分出来的一块缓存区,要想在这个缓存中保存数据,可以使用一个描述文件(manifest file),列出要下载和缓存的资源. ...

  2. HTML5 离线缓存管理库

    一.HTML5离线缓存技术 支持离线缓存是HTML5中的一个重点,离线缓存就是让用户即使在断网的情况下依然可以正常的运行应用.传统的本地存储数据的方式有 localstorage,sessionsto ...

  3. HTML5离线Web应用实战:五步创建成功

    [IT168 技术]HTML5近十年来发展得如火如荼,在HTML 5平台上,视频,音频,图象,动画,以及同电脑的交互都被标准化.HTML功能越来越丰富,支持图片上传拖拽.支持localstorage. ...

  4. 吓哭原生App的HTML5离线存储技术,却出乎意料的容易!【低调转载】

    吓哭原生App的HTML5离线存储技术,却出乎意料的容易![WeX5低调转载] 2015-11-16 lakb248 起步软件 近几天,WeX5小编编跟部分移动应用从业人士聊了聊,很多已经准备好全面拥 ...

  5. HTML5离线缓存问题

    HTML5离线缓存问题 1.应用程序缓存 什么是应用程序缓存(Application Cache)? HTML5 引入了应用程序缓存,这意味着 web 应用可进行缓存,并可在没有因特网连接时进行访问. ...

  6. HTML5离线存储原理

    找到一篇介绍离线缓存的,感觉比之前看到的解释的更透彻,新的知识点记录如下: 大家都知道Web App是通过浏览器来访问的,所以离线状态下是无法使用app的.其中web app中的一些资源并不经常改变, ...

  7. 使用 jQuery Mobile 与 HTML5 开发 Web App —— HTML5 离线缓存

    本文要介绍的,是 HTML5 离线网络应用程序的特性,离线网络应用程序在 W3C 中的实际名称是 "Offline Web applications" ,也称离线缓存.当用户打开浏 ...

  8. 处理html5离线应用程序存储的一些问题。

    manifest方法引入appcache文件,缓存页面,是html5的新特性,通过加载一次,下次自动读取缓存,加载速度快,离线也能加载.缺点就是,被加载的页面会被强制缓存所有的内容. 为了解决不加载所 ...

  9. 神奇的HTML5离线存储(应用程序缓存)

    声明:本文为原创文章,如需转载,请注明来源并保留原文链接前端小尚,谢谢! 前言 使用 HTML5,通过创建 cache manifest 文件,可以轻松地创建 web 应用的离线版本. HTML5引入 ...

随机推荐

  1. $watch $apply and $evalAsync vs $timeout

    $watch $scope对象上的$watch方法会给Angular事件循环内的每个$digest调用装配一个脏值检查. 如果在表达式上检测到变化, Angular总是会返回$digest循环. $w ...

  2. fool

    from PIL import Imageimg = Image.open("D:\\pic2\\CZA3302.png")(w,h) = img.sizeim=img.conve ...

  3. AC日记——鬼谷子的钱袋 codevs 2998

    2998 鬼谷子的钱袋 2006年省队选拔赛湖南  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 大师 Master    题目描述 Description 鬼谷子非常聪明,正 ...

  4. Pig与Hive的区别

    Language 在Hive中可以执行  插入/删除 等操作,但是Pig中我没有发现有可以 插入 数据的方法,请允许我暂且认为这是最大的不同点吧. Schemas Hive中至少还有一个“表”的概念, ...

  5. jQuery无缝循环开源多元素动画轮播jquery.slides插件

    详细内容请点击 初始化插件: 一款基于jQuery无缝轮播图插件,支持图内元素动画,可以自定义动画类型$(".slideInner").slide({slideContainer: ...

  6. mysql千万级测试1亿数据的分页分析测试

    本文为本人最近利用几个小时才分析总结出的原创文章,希望大家转载,但是要注明出处 http://blog.sina.com.cn/s/blog_438308750100im0e.html 有什么问题可以 ...

  7. 【Spark学习】Apache Spark安全机制

    Spark版本:1.1.1 本文系从官方文档翻译而来,转载请尊重译者的工作,注明以下链接: http://www.cnblogs.com/zhangningbo/p/4135808.html 目录 W ...

  8. SICP中sqrt(开方)的实现(附C#实现)

    #lang racket (define (square x) (* x x)) (define (sqrt-iter guess x) (if (good-enough? guess x) gues ...

  9. 使用OpenCV进行网络摄像头的图像采集及视频存储

    rtspURL格式 rtsp://[username]:[password]@[ip]:[port]/[codec]/[channel]/[subtype]/av_stream 1) username ...

  10. 【Java框架型项目从入门到装逼】第五节 - 在Servlet中接收和返回数据

    在上一节的程序中,我们可以看到HttpServletRequest, HttpServletResponse这两个对象.可以说,这是JavaWeb中至关重要的两个对象.接下来,我们来做一个简短的说明: ...