h5离线缓存

1. 协议缓存

举个例子:
更新了一张图片,发布之后反复重新进页面总是看不到更新

说明是协议缓存?

http协议缓存机制是指通过HTTP协议头里的Cache-Control(或 Expires)和Last-Modified(或Etag)等字段来控制文件缓存的机制。

  • Cache-Control 用于控制文件在本地缓存有效时长。最常见的,比如服务器回包:Cache-Control:max-age=600 表示文件在本地应该缓存,且有效时长是600秒(从发出请求算起)。在接下来600秒内,如果有请求这个资源,浏览器不会发出 HTTP 请求,而是直接使用本地缓存的文件。
  • Last-Modified 是标识文件在服务器上的最新更新时间。下次请求时,如果文件缓存过期,浏览器通过 If-Modified-Since 字段带上这个时间,发送给服务器,由服务器比较时间戳来判断文件是否有修改。如果没有修改,服务器返回304告诉浏览器继续使用缓存;如果有修改,则返回200,同时返回最新的文件。

Cache-Control 还有一个同功能的字段:Expires。Expires 的值一个绝对的时间点,如:Expires: Thu, 10 Nov 2015 08:45:11 GMT,表示在这个时间点之前,缓存都是有效的。

Expires 是 HTTP1.0 标准中的字段,Cache-Control 是 HTTP1.1 标准中新加的字段,功能一样,都是控制缓存的有效时间。当这两个字段同时出现时,Cache-Control 是高优化级的。

Etag 也是和 Last-Modified一样,对文件进行标识的字段。不同的是,Etag的取值是一个对文件进行标识的特征字串。在向服务器查询文件是否有更新时,浏览器通过If-None-Match 字段把特征字串发送给服务器,由服务器和文件最新特征字串进行匹配,来判断文件是否有更新。没有更新回包304,有更新回包200。Etag和Last-Modified可根据需求使用一个或两个同时使用。两个同时使用时,只要满足其中一个条件,就认为文件没有更新

不过有两种情况比较特殊:

  • 手动刷新页面(F5):
    浏览器会直接认为缓存已经过期(可能缓存还没有过期),在请求中加上字段:Cache-Control:max-age=0,发包向服务器查询是否有文件是否有更新。
  • 强制刷新页面(Ctrl+F5):
    浏览器会直接忽略本地的缓存(有缓存也会认为本地没有缓存),在请求中加上字段:Cache-Control:no-cache(或Pragma:no-cache),发包向服务重新拉取文件。

2. 应用缓存(离线缓存)

除了http协议缓存,HTML5 提供一种应用程序缓存机制,使得基于web的应用程序可以离线运行。为了能够让用户在离线状态下继续访问 Web 应用,开发者需要提供一个 cache manifest 文件。这个文件中列出了所有需要在离线状态下使用的资源,浏览器会把这些资源缓存到本地。
虽然manifest的技术已被web标准废弃, 但这不影响我们尝试去了解它. 也正是因为manifest的应用缓存机制如此诱人, 饿了么 和 office 365邮箱等都还在使用着它!

使用方法:

<!-- index.html -->
<!DOCTYPE HTML>
<html manifest="test.manifest">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="/appactivity/testmain/css/index.css">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    我是哈哈哈哈哈
</body>
</html>

注意事项:

  • 如何开启缓存:
<html manifest="test.manifest">
  ...
</html>

在html标签中指定manifest文件, 便表示该网页使用manifest进行离线缓存. 该网页内需要缓存的文件列表需要在 test.manifest 文本文件中指定.

  • manifest缓存清单

就像写作文一样, manifest采用经典的三段式. 分别为: CACHE, NETWORK 和 FALLBACK. 如下, 先看一个栗子?:

#test.manifest文件
CACHE MANIFEST
# Time: Sat Jun 04 2016 17:11:50 GMT+0800 (CST)
# webpack-multipage v1.0.0==== ========

CACHE:
css/index.css

NETWORK:
js/app.js

FALLBACK:
/other 404.html

第一行必须以 CACHE MANIFEST 开头, 后可跟若干字符注释, 注释从#号开始. 跟在 CACHE MANIFEST 行后的文件。

第一段内容以 CACHE: 开头

每行列出一个, 这些文件是需要缓存的文件. 因此 index.css 会被缓存, 不需要访问网络.

第二段内容以 NETWORK: 开始

跟在该行后的文件表示需要访问网络. 如: app.js 将直接从网络上下载, 并不走manifest cache, 如果除了第一段中缓存的文件以外, 其他文件都从网络上获取, 那么此时可将 app.js 改为 * (通配符).

第三段内容以 FALLBACK: 开始

跟在该行后的文件表示会有一个替代方案. 如: 当访问 /other 路径时, 如果访问失败, 那么将自动加载 404.html 作为替代.

  • manifest缓存状态

每个manifest缓存都有一个状态, 标示着缓存的情况. 一份缓存清单只有一个缓存状态, 即使它被多个页面引用. 以下是各个缓存状态:

  1. UNCACHED(未缓存): 表明应用缓存对象还没有初始化完成.
  2. IDLE(空闲): 应用缓存并未处于更新状态.
  3. CHECKING(检查): 正在检查是否存在更新.
  4. DOWNLOADING(下载): 清单更新后, 重新下载全部资源到临时缓存中.
  5. UPDATEREADY(更新就绪): 新版本的缓存下载完成, 全部就绪, 随即触发事件 updateready.
  6. OBSOLETE(废弃): 应用缓存已被废弃.
  • applicationCache
//webview下
var cache = window.applicationCache;
//shared worker中
var cache = self.applicationCache;

以下是属性和方法:

  1. status: 返回当前页面的应用缓存的状态, 通常开启应用缓存的页面可能返回1, 其他页面则返回0.

  2. update(): 手动触发应用缓存的更新.

注意:

(1) 若有更新, 则依次触发①检查事件(Checking event), ②下载事件(Downloading event), ③下载进度事件(Progress event), ④更新完成事件(UpdateReady event);

(2) 若无更新, 则依次触发①检查事件(Checking event), ②无更新事件(NoUpdate event);

(3) 在未开启应用缓存的页面调用将抛出Uncaught DOMException 错误.

update() 方法通常在长时间不关闭的页面使用, 比如说邮箱应用, 用于定期检测可能的更新.

  1. abort(): 取消应用缓存的更新. 可用于节省有限的网络带宽.
  2. swapCache(): 如果存在一个更新版本的应用缓存, 那么它将切换过去, 否则将抛出 Uncaught DOMException 错误. 通常, 我们会在updateready事件触发之后手动调用swapCache()方法, swapCache的切换只对后续加载的缓存文件有效, 已经加载成功的资源并不会重新加载.

那么如何利用好上述api更新一个页面的应用缓存呢? 别急, Beginner’s Guide to Using the Application Cache 一文中提供了如下的样板方法:

// Check if a new cache is available on page load.
window.addEventListener('load', function(e) {
  window.applicationCache.addEventListener('updateready', function(e) {
    if (window.applicationCache.status == window.applicationCache.UPDATEREADY) {
      // Browser downloaded a new app cache.
      // Swap it in and reload the page to get the new hotness.
      window.applicationCache.swapCache();
      if (confirm('A new version of this site is available. Load it?')) {
        window.location.reload();
      }
    } else {
      // Manifest didn't changed. Nothing new to server.
    }
  }, false);
}, false);
  • 服务器配置方法

    nginx:

    1. 找到Ngnix服务器配置文件mime.types
    2. 编辑mime.types
    3. 添加manifest文件映射
types {  
      text/html                             html htm shtml;  
      text/css                              css;  
      text/xml                              xml rss;  
      image/gif                             gif;  
      image/jpeg                            jpeg jpg;  
      application/x-javascript              js;  
      application/atom+xml                  atom;  
    
      text/mathml                           mml;  
      text/plain                            txt;  
      text/vnd.sun.j2me.app-descriptor      jad;  
      text/vnd.wap.wml                      wml;  
     text/x-component                      htc;  
   
      image/png                             png;  
     image/tiff                            tif tiff;  
      image/vnd.wap.wbmp                    wbmp;  
      image/x-icon                          ico;  
      image/x-jng                           jng;  
     image/x-ms-bmp                        bmp;  
      image/svg+xml                         svg;  
    
      application/java-archive              jar war ear;  
      application/mac-binhex40              hqx;  
      application/msword                    doc;  
     application/pdf                       pdf;  
      application/postscript                ps eps ai;  
      application/rtf                       rtf;  
      application/vnd.ms-excel              xls;  
      application/vnd.ms-powerpoint         ppt;  
     application/vnd.wap.wmlc              wmlc;  
      application/vnd.wap.xhtml+xml         xhtml;  
      application/x-cocoa                   cco;  
      application/x-java-archive-diff       jardiff;  
      application/x-java-jnlp-file          jnlp;  
      application/x-makeself                run;  
      application/x-perl                    pl pm;  
      application/x-pilot                   prc pdb;  
      application/x-rar-compressed          rar;  
      application/x-RedHat-package-manager  rpm;  
      application/x-sea                     sea;  
      application/x-shockwave-flash         swf;  
      application/x-stuffit                 sit;  
      application/x-tcl                     tcl tk;  
      application/x-x509-ca-cert            der pem crt;  
      application/x-xpinstall               xpi;  
      application/zip                       zip;  
    
      application/octet-stream              bin exe dll;  
      application/octet-stream              deb;  
      application/octet-stream              dmg;  
      application/octet-stream              eot;  
      application/octet-stream              iso img;  
      application/octet-stream              msi msp msm;  
    
      audio/midi                            mid midi kar;  
      audio/mpeg                            mp3;  
     audio/x-realaudio                     ra;  
   
      video/3gpp                            3gpp 3gp;  
     video/mpeg                            mpeg mpg;  
      video/quicktime                       mov;  
     video/x-flv                           flv;  
      video/x-mng                           mng;  
      video/x-ms-asf                        asx asf;  
      video/x-ms-wmv                        wmv;  
     video/x-msvideo                       avi;  
      application/x-nokia-widget            wgz;  
    
      text/cache-manifest                   mf manifest;  
  }  

4. 重启nginx

注意: manifest后面一定要加

  • manifest缓存规则
  1. 遵循全量缓存的规律. 即: manifest文件改动后, 将重新缓存一遍所有的文件(包括html本身和动态添加的需要缓存的文件,即使缓存列表中没有该html). 第一次缓存过程中如果出现缓存失败的文件, 那么, 第二访问, 又将重新缓存一遍所有的文件. 以此类推.
  2. manifest文件本身不能写进缓存清单, 否则连同html和资源在其缓存失效之前, 将永远不能获得更新.
  3. 即使manifest文件丢失, 缓存依然有效. 不过从此以后, 引入该manifest的html, 将永远不能获得更新.
  • webview的缓存现象

通常, webview的缓存有如下三种现象:

  1. 普通网页(无manifest文件), 不受manifest缓存影响, 缓存只走 http cache.
  2. 包含manifest文件的网页, 缓存文件只受manifest缓存影响(只有manifest文件改变时才会更新缓存资源), 缓存资源完全与 http cache 无关, 但是 NETWORK 段落后需要访问网络的文件, 将继续走 http cache.
  3. webview直接加载manifest缓存过的文件时, 优先加载第一个manifest缓存的该文件, 如果没有找到manifest缓存, 那么它将自动寻找 http cache 或者 在线加载.
  • 最佳实践
  1. 通常只使用一个manifest文件, 并保证缓存的文件尽可能的少, 以减小manifest每次更新清单中文件所耗费的时间和流量.
  2. 如果一定要使用两个及以上manifest文件, 缓存文件请尽量不要相同.
  3. 如果以上两条都不能保证, 那么, 请保证尽可能在manifest缓存的状态更新时, 主动去刷新网页.(此时并不能保证不同网页之间同一个缓存文件版本一致)
  • 具体落地步骤
  1. 如果缓存的文件需要加参数运行, 建议将参数内容加到hash中, 如:cached-page.html#parameterName=value
  2. manifest 的引入可以使用绝对路径或者相对路径, 如果你使用的是绝对路径, 那么你的manifest文件必须和你的站点处于同一个域名下.
  3. manifest文件你可以保存为任意的扩展名, 但是响应头中以下字段须取以下定值, 以保证manifest文件正确被解析, 并且它没有http缓存
Content-Type: text/cache-manifest
Cache-Control: max-age=0
Expires: [CURRENT TIME]
  • 总结
  1. 离线缓存与传统浏览器缓存区别:

浏览器缓存(Browser Caching)是为了节约网络的资源加速浏览,浏览器在用户磁盘上对最近请求过的文档进行存储,当访问者再次请求这个页面时,浏览器就可以从本地磁盘显示文档,这样就可以加速页面的阅览

区别

  • 离线缓存是针对整个应用,浏览器缓存是单个文件

  • 离线缓存断网了还是可以打开页面,浏览器缓存不行

  • 离线缓存可以主动通知浏览器更新资源

本地存储和离线存储有什么不同

  • 本地存储与离线缓存都是为了方便网页的加载,提高用户体验等。

  • 本地存储一般存储的都是数据,而离线缓存一般存储的是网页等。

  1. 试用场景
  • 单地址的页面
  • 对实时性要求不高的业务
  • 离线的webapp
  1. 优点
  • 完全离线
  • 资源被缓存,加载更快
  • 降低server负载
  1. 缺点
  • 含有manifest属性的当前请求页无论如何都会被缓存;
  • 更新需要建立在manifest文件的更新,文件更新后是需要页面再次刷新的(需要2次刷新才能获取资源);
  • 更新是全局性的,无法单独更次年某个文件,即一个文件被更新,需要拉取全部文件来更新;
  • 对于链接的参数变化是敏感的,任何一个参数的修改都会被(master)重新缓存(重复缓存含参页面)index.html和Index.html?renew=1会被认为是不同文件,分别缓存
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章