首页 > 代码库 > html5的离线存储问题汇总

html5的离线存储问题汇总

       HTML5的一个重要特性就是离线存储,所谓的离线存储就是将一些资源文件保存在本地,这样后续的页面重新加载将使用本地资源文件,在离线情况下可以继续访问web应用,同时通过一定的手法(更新相关文件或者使用相关API),可以更新、删除离线存储等操作;

       HTML5的离线存储使用一个manifest文件来标明哪些文件是需要被存储的,使用如 <html manifest=‘offline.manifest‘> 来引入一个manifest文件,这个文件的路径可以是相对的,也可以是绝对的,如果你的web应用很多,而且希望能集中管理manifest文件,那么静态文件服务器是个不错的选择。

对于manifest文件,要求:文件的mime-type必须是 text/cache-manifest类型。如果你是JAVA工程,在你的web.xml中配置请求后缀为manifest的格式:

[html] view plaincopy
  1. <mime-mapping>  
  2.         <extension>manifest</extension>  
  3.         <mime-type>text/cache-manifest</mime-type>  
  4. </mime-mapping>    
这样可以控制请求到的manifest文件格式为text/cache-manifest的。

 manifest文件的格式:

[html] view plaincopy
  1. CACHE MANIFEST  
  2. # 这一句必须存在,而且必须放在头部  
  3. # 指明缓存入口  
  4. CACHE:  
  5. index.html  
  6. style.css  
  7. images/logo.png  
  8. scripts/main.js  
  9. # 以下资源必须在线访问  
  10. NETWORK:  
  11. login.php  
  12. # 如果index.php无法访问则用404.html代替  
  13. FALLBACK:  
  14. /index.php /404.html  

       其中 CACHE 不是必须存在的,可以直接在 CACHE MANIFEST 行之下直接写需要缓存的文件,在这里指明的文件将被缓存到浏览器本地。在NETWORK之下指明的文件,是强制必须通过网络资源获取的,在FALLBACK下指明的是一种失败的回调方案,比如上述index.php无法访问,那么就发出404.htm请求

这样几步就可以完成对离线存储的支持。接下来要思考的,是如何更新离线存储?

      当用户本地再次联网的时候,本地的离线存储资源需要检查是否需要更新,这个更新过程,也是通过manifest的更新来控制的,更新了manifest文件,浏览器会自动的重新下载新的manifest文件并在下一次刷新页面的时候进行资源文件的重新请求(第三次刷新替换本地缓存为最新缓存),而且这个请求是全局性的,也就是所有在manifest缓存列表中的文件都会被请求一次,而不是单独请求某个特定修改过的资源文件,因为manifest是不知道哪个文件被修改过了的。

       对于全局更新的担心是不必要的,因为对于没有更新过的资源文件,请求依旧是304响应,只有真正更新过的资源文件才是200.

关于304响应:

        如果客户端发送的是一个条件验证(Conditional Validation)请求,则web服务器可能会返回HTTP/304响应,这就表明了客户端中所请求资源的缓存仍然是有效的,也就是说该资源从上次缓存到现在并没有被修改过.条件请求可以在确保客户端的资源是最新的同时避免因每次都请求完整资源给服务器带来的性能问题.

服务器会读取到这两个请求头中的值,判断出客户端缓存的资源是否是最新的,如果是的话,服务器就会返回HTTP/304 Not Modified响应,但没有响应体.客户端收到304响应后,就会从缓存中读取对应的资源.

当客户端缓存了目标资源但不确定该缓存资源是否是最新版本的时候,就会发送一个条件请求.在Fiddler中,你可以在Headers Inspector查找相关请求头,这样就可以辨别出一个请求是否是条件请求.

在进行条件请求时,客户端会提供给服务器一个If-Modified-Since请求头,其值为服务器上次返回的Last-Modified响应头中的日期值,还会提供一个If-None-Match请求头,值为服务器上次返回的ETag响应头的值:

另一种情况是,如果服务器认为客户端缓存的资源已经过期了,那么服务器就会返回HTTP/200 OK响应,响应体就是该资源当前最新的内容.客户端收到200响应后,就会用新的响应体覆盖掉旧的缓存资源.

只有在客户端缓存了对应资源且该资源的响应头中包含了Last-ModifiedETag的情况下,才可能发送条件请求.如果这两个头都不存在,则必须无条件(unconditionally)请求该资源,服务器也就必须返回完整的资源数据.


     所以控制离线存储的更新,需要2个步骤,一是更新资源文件,二是更新manifest文件,特别的,更新manifest文件是不需要修改什么特定内容的,只要是这个文件随意一处被修改,那么浏览器就会感知,对于我们的资源文件通常名称是固定的,比如xxx.css,更新内容不会带有文件名更新的情况下,需要更新manifest文件怎么操作呢?一个比较好的方式是更新任意一处# 开头的注释即可,其目的只是告诉浏览器这个manifest文件被更新过。

以上的这些内容,其更新操作都是浏览器自动完成的。同样的,W3C定义了离线存储的API规范:http://www.whatwg.org/specs/web-apps/current-work/#applicationcache

另外离线缓存需要注意以下几点:

1、可以通过iframe嵌入多个manifest文件。主页不需要配置manifest,这样index.html就不会被缓存。 
<iframe id="iframe1" src=http://www.mamicode.com/"cache1.html" frameborder="no" scrolling="no">
        </iframe> 
<iframe id="iframe2" src=http://www.mamicode.com/"cache2.html" frameborder="no" scrolling="no">
        </iframe> 
<iframe id="iframe2" src=http://www.mamicode.com/"cache3.html" frameborder="no" scrolling="no">
        </iframe> 
2、多个manifest文件还是会有空间的限制,在ipad的safari上不能超过50M。若cache1.manfest是26M,cache1.manfest是27M,则2个加起来超过50m,这时,首先cached完cache1,当缓存cache2的时候,会报一个超过缓存容量限制的错误。cache3自然也不会保存了。只保存了第一个cache1. 
3、必须reload页面才会使缓存更新生效。 
4、手动检查cache的更新。applicationCache.update(); 
5、手动执行更新。 
applicationCache.addEventListener("updateready", function() { 
         if (confirm("本地缓存已被更新,是否刷新?")) { 
        // (3) 手工更新本地缓存 
            applicationCache.swapCache(); 
            // 重载画面 
            location.reload(); 
        } 
    }, true); 
applicationCache.swapCache();必须放在updateready中执行。 
6、manifest文件中的配置文件可以不被html使用。但是若缓存xml等文件,好像缓存不了。 
7、NETWORK:若除了CACHE:定义的文件之外的文件都不要缓存,则NETWORD:下必须写个*.否则可能造成CACHE外的文件全部加载不了。 
8、CACHE:下不能使用文件夹形式定义。如images/。这样方式不会被识别。 
而且文件路径和文件名不能包含空格,否则只会取得空格之前的文本,导致文件缓存失败。 
9、若manifest文件删除了之前缓存的文件,则浏览器也会删除缓存的文件并更新。