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

 一、些许前提

最近在制作一个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是离线应用的缓存. 他们各自的更新机制如下:

 

Browser cache

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了, 因此抓包也看不到任何请求. 它的流程应该是这样的:

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Qt是一个功能强大的开发框架,通过使用Qt的地图和位置相关API,可以实现离线地图和定位的功能。 要实现离线地图,可以使用OpenStreetMap(OSM)提供的地图数据。首先,需要下载适合离线使用的OSM地图数据文件,通常以OSM格式或PBF格式保存。然后,使用Qt的地图显示控件(如QQuickMapItem或QMapboxGL)加载这些地图数据文件,并显示地图内容。可以设置控件的初始位置和缩放级别,以及地图的细节级别。通过这种方式,就可以在应用程序中加载和显示离线地图了。 要实现定位功能,可以使用Qt的位置服务相关API。通过调用QGeoPositionInfoSource类,可以获取位置信息,其中包括经纬度、海拔、速度等。可以设置定位更新频率和准确度要求。可以使用QGeoCoordinate类来表示地理坐标。通过在地图上显示当前位置,可以实现定位功能的可视化展示。 为了实现离线地图和定位的功能,还需要考虑一些问题。首先,需要解决地图数据的存储问题,可以选择将地图数据存储在本地设备上,或者在应用程序中将地图数据打包并随应用程序一起发布。此外,需要考虑到地图数据的更新和管理,可以使用定期下载最新的地图数据文件,以保持地图数据的最新状态。另外,还需要处理位置信息的更新和处理,以及与地图控件的交互逻辑。 总而言之,通过使用Qt的地图和位置相关API,可以方便地实现离线地图和定位的功能。通过加载和显示离线地图数据,并获取和展示位置信息,可以为应用程序增加地图和定位的功能,提升用户体验。 ### 回答2: Qt 是一种流行的跨平台应用程序开发框架,它可以实现离线地图和定位功能。 要实现离线地图,可以使用 Qt 的 QML (Qt Quick) 技术来创建用户界面。首先,需要将离线地图数据以及相关元数据导入到应用程序中。可以使用一些开放源代码的地图数据集,比如 OpenStreetMap (OSM) 数据。将 OSM 数据转换为可用的地图矢量切片,然后利用 Qt 提供的图形绘制功能来绘制这些矢量切片。同时,通过使用离线地图数据,可以将地图数据存储在本地,从而用户无需联网也能够查看地图。此外,可以通过添加一些额外的功能来提高离线地图的用户体验,比如地点搜索、缩放和导航等。 要实现定位功能,可以使用 Qt 的位置服务模块。位置服务模块提供了一种简便的方法来获取设备的位置信息。可以使用 Qt 定位服务模块来获取设备的经纬度坐标,然后在地图上以标记的方式显示用户的当前位置。可以使用位置服务模块的 API 来获取设备的当前位置信息,同时还可以利用其它的功能,比如计算两点之间的距离和方位角等。定位功能可以与离线地图功能结合使用,帮助用户在地图上准确显示自己的位置,并根据需要进行导航。 总之,Qt 可以通过使用离线地图和定位服务模块来实现离线地图和定位功能。这使得开发者可以轻松创建具有离线地图和定位功能的应用程序,提供更好的用户体验和功能。 ### 回答3: Qt是一个功能强大的跨平台应用程序开发框架,可以用来实现离线地图和定位功能。 要实现离线地图功能,可以使用Qt提供的WebEngine模块。首先,需要准备一张离线地图数据,可以是由其他地图平台下载得到的离线瓦片地图数据。然后,使用QWebEngineView类创建一个Web视图,并通过调用其load()方法加载离线地图的HTML页面。在HTML页面中,使用OpenLayers或Leaflet等JavaScript库来显示和操作地图数据。通过JavaScript和Qt之间的交互,可以实现地图的缩放、漫游和标注等功能。 要实现定位功能,可以利用Qt提供的位置服务框架。首先,需要在应用程序中请求定位权限。然后,使用QGeoPositionInfoSource类访问设备的位置信息。通过调用其startUpdates()方法,可以开始获取位置更新,并通过slot函数接收和处理更新的位置信息。位置信息包括经度、纬度、高度和时间等。 在具体实现中,可以将地图显示和定位功能集成在一个Qt应用程序中。用户可以通过界面交互选择要显示的地图区域,通过手势操作或按钮点击来缩放和漫游地图。同时,可以通过获取当前位置信息,并在地图上显示出来。 总之,Qt提供了丰富的功能和工具,可以很方便地实现离线地图和定位功能。开发者只需根据具体需求,选择合适的组件和类来完成实现。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值