HTML5离线应用
间断性网络一直是目前手机web应用的老大难问题,手机网络的低速不稳定以及低流量导致web应用和native应用在响应和消耗上都差了一个数量级。
HTML5离线应用就是为了解决在间断性网络下对服务端的强依赖问题。
HTML5离线介绍
一个完美的HTML5应用首先需要能够做到展示层(HTML)和数据层逻辑层(javascript)分离。一般的做法是:HTML静态,通过javascript请求服务端数据,回填页面。
一个HTML5离线应用需要由开发者书写离线声明,离线声明里包括:哪些文件每次都读取缓存,哪些文件需要每次请求网络,哪些文件可以折中(折中的意思就是:有网络的时候用网络,无网络的时候用本地缓存)。
有了这份离线声明,浏览器(当然包括手机端的webview)就会按照你的声明来请求数据,一个完美的HTML5离线应用能最大限度的节约流量。
HTML5离线应用示例
http://jdy.tmall.com/offline/toolbar.html
http://jindoucloud.aliapp.com/item/item.html
上面两个示例,您可以在读完本文后,再对照着看看。您可以在联网和断开网络的情况下访问看看。
详解离线声明
如何书写
离线声明一般我们称之为manifest文件,下面是一个manifest文件的示例:
CACHE MANIFEST
#注释用#号
#这两个文件缓存
http://l.tbcdn.cn/apps/top/c/util/zepto.min.js
http://l.tbcdn.cn/apps/top/c/sdk-mobile.js
NETWORK:
#这些路径每次都网络请求
http://img01.taobaocdn.com/top/i1/
http://img01.daily.taobaocdn.net/sns_album/
http://log.mmstat.com/
FALLBACK:
#这些折中
/ajax/ ajax.html
如何使用
接下来我们只需要在HTML页面里加上这份离线声明。
<html manifest='application.manifest'>
</html>
不要以为到这里就大功告成了,有个关键的点还没有说到,当你的html标签里加入manifest标记,浏览器就会自动请求application.manifest路径获取离线声明文件,你需要把离线声明文件放入配置的路径上,同时在http响应头里声明Content-Type的类型为text/cache-manifest。
这也意味着,其实浏览器辨认离线声明文件是通过类型是cache-manifest,而不是通过后缀名。所以,你完全可以给你的离线声明文件命名为zhudi.offline。
Content-Type text/cache-manifest manifest;charset=UTF-8
这样就大功告成了。
别急,往下看,否则会遇到很多莫名其妙的问题
如何升级
需要升级离线的文件很简单,只需要修改一下application.manifest文件即可。用户下次打开HTML页面,浏览器判断application.manifest文件的MD5值不一致,浏览器会在后台默默请求服务端的最新的缓存文件。
你完全可以在文件里加一行注释,这样MD5值就不一样了,浏览器也会重新更新应用。
这也就是说:
- 用户每次打开你的HTML页面,至少会请求application.manifest文件一次(这次请求其实还能节约,这个后面再说)
- 当application.manifest升级,用户打开你的HTML页面时,浏览器会在后台请求最新的数据,但是本次展示的还是老的HTML资源。用户需要下次进入的时候才能看到最新的页面(这个也能通过JS避免,不过其实没这个必要)
- 一旦application.manifest升级,浏览器会下载所有的mainfest文件里声明的所有离线资源,即使你只更新了一个文件。(这个也有节省的办法,后面会说到)
需要注意
缓存区不支持通配符
这是HTML5使用起来最不方便的地方,在你声明哪些文件需要缓存的时候,不能够使用通配符和上层路径,必须具体到某个资源。NETWORK区域和FALLBACK区域可以。这也是和HTML5离线应用的处理机制有关,他的缓存不是等到页面里使用的时候再去判断,而是在获取到离线声明文件后,就开始后台下载所有声明的离线文件。
离线声明文件不容错
需要注意manifest文件是不容错的,也就是说你的离线声明文件一旦配置错误,将导致离线声明失效,应用将退化到普通HTML应用,而不会有任何提醒。
所以你每次修改离线文件,最好校验一次,校验办法为
访问一次你的网页(请用高级浏览器,IE慎用),看是否正常显示,然后拉掉网线,继续访问一次。
哪些情况下,会被认为离线文件配置错误呢?
- 文件不符合规定,比如写错了NETWORK
- Content-Type 不正确
- 缓存声明区包含不存在的资源文件。这个需要尤其注意
不支持IP
HTML地址必须位于域名下,通过IP访问不支持。
默认处理
如果一个请求不在缓存声明中,也不符合折中和网络规则,那么这次网络请求会被取消。所以一般的做法有两种:
- 在NETWORK里配置一个*(上线推荐)
- 配置一个折中方案,把*引导到一个JS上,该JS弹出alert。(开发阶段推荐,这样有利于及时发现遗漏的未配置的可缓存资源)
高级进阶
HTML5离线更像一个应用层面的东西,所以我们原来应用在每次http请求上的缓存策略可以继续使用。
这不得不和大家回顾下经常使用的两种http的缓存策略。
- max-age 在请求的返回头里加上max-age头,浏览器会按照max-age里给的时间进行本地缓存。在用户不强刷等其他外力影响下,理论上,在max-age时间内,不会发起任何请求。这也就意味着缓存时间内,无法更新。
- last-modified 在请求的返回头里加上last-modified:Fri, 12 May 2006 18:53:33 GMT头,那么浏览器在下次请求的时候会带上If-Modified-Since:Fri, 12 May 2006 18:53:33 GMT的头,服务端判断无更新,则返回HTTP 304 (Not Changed.)状态码。
max-age节约请求。last-modified节约流量。
再回到HTML5离线应用,一次请求根据离线声明的判断需要发起网络请求,那么接下来会做HTTP级别的缓存策略的判断,如果在max-age范围内,会直接用本地版本返回,如果不在max-age范围内,接下来就走last-modified的逻辑。
那么如何节约application.manifest的请求次数或者流量,或者如何节约application.manifest升级时资源文件下载消耗的流量是不是很清楚了?
顺便说一下
从千牛1.1.2开始,支持从JS发起top的请求了。这样大家的显示层(HTML)逻辑层(JS)都被离线缓存,数据层直接通过JS发起到TOP。大家的服务端是不是变的很轻量啊。赶快TKS放翁朱棣君彦……demo实例:商品管理 http://jindoucloud.aliapp.com/item/item.html