H5是现在几乎每个App都会使用的技术,具有开发周期快、成本低、灵活性好的特点,但也有致命的缺点,响应速度慢、用户体验卡顿,所以优化webview性能对Android开发很重要,而缓存是优化webview很有效的手段,本文介绍webview自身的缓存机制和优缺点。
webview的两类缓存机制
一类是Http协议缓存,是所有浏览器都支持的,通过http协议设置的一套缓存统一规则,
另一类是H5应用缓存,是由前端开发人员设置的,
- Dom Storgage(Web Storage)存储机制
- Web SQL Database存储机制
- Indexed Database(IndexedDB)
- Application Cache(AppCache)机制
- File System API
协议缓存机制 原理: 协议缓存机制主要是根据HTTP协议头里的Cache-Control、Expires、Last-Modified以及Etag请求头控制缓存,缓存配置主要是web前端和后台设置。 - Cache-Control 用于控制文件在本地缓存有效时长。最常见的,比如response header中设置:Cache-Control:max-age=2592000 表示文件在本地应该缓存,且有效时长是2592000秒。在过期时间内,如果客户端发送相同的请求,浏览器不会发出 HTTP 请求,而是直接使用本地缓存的文件。
- Last-Modified:包含源头服务器认定的资源做出修改的日期及时间,用于标识文件在服务器上的最新更新时间。判断接收到的或者存储的资源是否彼此一致,再次请求时,如果文件缓存过期,浏览器通过If-Modified-Since字段带上这个时间,发送给服务器,由服务器比较时间戳来判断文件是否有修改。如果请求的资源从接收的那时起未经修改,那么返回一个不带有消息主体的304响应告知浏览器使用缓存。否则就返回200,同时返回最新的资源。
- Expires:作用和Cache-Control类似,响应头包含日期/时间(格林尼治时间),表示在此时候之后,响应过期。在Expires设置的时间之前,浏览器不会再次请求获取资源的。但如果本地时间和服务器时间不同步就会导致出现问题,因此才会有了上面的Cache-Control。需要注意的是,Cache-Control的优先级比Expires要高。如果在Cache-Control响应头设置了max-age,那么Expires头会被忽略。示例:Expires: Fri, 24 Sep 2021 09:09:24 GMT
- ETag:作用和Last-Modified类似,标识文件在服务器上的最新更新时间。不同的是,ETag的值是一个对文件进行标识的特征字串。在向服务器查询文件是否有更新时,浏览器通过If-None-Match字段把特征字串发送给服务器,服务器将客户端的ETag与其当前版本的资源的ETag进行比较,如果两个值匹配(即资源未更改),服务器将返回不带任何内容的304未修改状态告知浏览器使用缓存。没有明确指定生成ETag值的方法。通常,使用内容的散列,最后修改时间戳的哈希值,或简单地使用版本号。ETag和Last-Modified可根据需求使用一个或两个同时使用。两个同时使用时,只要满足基中一个条件,就认为文件没有更新。
常见用法: Cache-Control 通常与 Last-Modified 一起使用。一个用于控制缓存有效时间,一个在缓存失效后,向服务查询是否有更新。 Expires与 Etag一起使用。Expires 的值一个绝对的时间点,如:Expires: Fri, 24 Sep 2021 09:09:24 GMT,表示在这个时间点之前,缓存都是有效的。 Expires 是 HTTP1.0 标准中的字段,Cache-Control 是 HTTP1.1 标准中新加的字段,功能一样,都是控制缓存的有效时间。当这两个字段同时出现时,Cache-Control 是高优化级的。 还存在两种特殊情况: 1、手动刷新时(F5)浏览器会认为缓存已经过期,在请求中加上字段Cache-Control:max-age=0,直接向服务器查询是否有文件需要更新。 2、强制刷新页面(Ctrl+F5)时浏览器会直接忽略本地的缓存,在请求中加上字段Cache-Control:no-cache,直接向服务器请求新的资源。 特点: - 浏览器缓存的优势在于支持Http协议层。
不足之处有: - 需要首次加载之后才能产生缓存文件;
- 终端设备缓存的空间有限,系统给的空间太小,只有12M,缓存有可能会被清除;
- 缓存使用缺乏校验,有可能被篡改;
客户端实现: 浏览器缓存主要用于静态资源文件的存储,例如JS、CSS、字体、图片等资源,Webview会将缓存的文件记录及文件内容会存在当前app的data目录中。WebView内置自动实现,使用默认的CacheMode就可以实现。也可手动设置缓存模式:
WebSettings webSettings = webView.getSettings();
webSettings.setCacheMode(WebSettings.LOAD_DEFAULT);
缓存模式:
- LOAD_CACHE_ONLY:不使用网络,只读取本地缓存数据
- LOAD_DEFAULT:根据cache-control决定是否从网络上取数据
- LOAD_CACHE_NORMAL:API level 17中已经废弃,从API level 11开始作用同LOAD_DEFAULT模式
- LOAD_NO_CACHE:不使用缓存,只从网络获取数据
- LOAD_CACHE_ELSE_NETWORK:只要本地有,无论是否过期,或者no-cache,都使用缓存中的数据。本地没有缓存时才从网络上获取。
一般设置为默认的缓存模式就可以了。 H5应用缓存 1、Dom Storgage(Web Storage)存储机制 原理: 通过存储字符串的 Key - Value 对来提供 DOM Storage 分为 sessionStorage & localStorage; 二者使用方法基本相同,区别在于作用范围不同: - sessionStorage:具备临时性,即存储与页面相关的数据,它在页面关闭后无法使用
- localStorage:具备持久性,即保存的数据在页面关闭后也可以使用。
官方描述: DOM 存储是一套在 Web Applications 1.0 规范中首次引入的与存储相关的特性的总称,现在已经分离出来,单独发展成为独立的 W3C Web 存储规范。 DOM存储被设计为用来提供一个更大存储量、更安全、更便捷的存储方法,从而可以代替掉将一些不需要让服务器知道的信息存储到 cookies里的这种传统方法。 Dom Storage机制类似Cookies,但有一些优势。Dom Storage是通过存储字符串的Key-Value对来提供的, Dom Storage存储的数据在本地,不像Cookies,每次请求一次页面,Cookies都会发送给服务器。 特点: - 存储空间大( 5MB):存储空间对于不同浏览器不同,如Cookies 才 4KB
- 存储安全、便捷: Dom Storage 存储的数据在本地,不需要经常和服务器进行交互
- 不像 Cookies每次请求一次页面,都会向服务器发送网络请求
应用场景: 可用于存储临时的简单数据。作用机制类似于SharedPreference。但是,如果要存储结构化的数据,可能要借助JSON了,将要存储的对象转为JSON串 客户端实现:
webSettings.setDomStorageEnabled(true);
2、Web SQL Database存储机制 根据官方说明,Web SQL Database存储机制不再推荐使用(不再维护),取而代之的是 IndexedDB缓存机制。 原理: 基于 SQL 的数据库存储机制 特点:
- 充分利用数据库的优势,可方便对数据进行增加、删除、修改、查询
应用场景: 存储适合数据库的结构化数据 客户端实现:
WebSettings settings = getSettings();
String cacheDirPath = context.getFilesDir().getAbsolutePath()+"cache/";
settings.setDatabasePath(cacheDirPath);
settings.setDatabaseEnabled(true);
3、Indexed Database(IndexedDB) IndexedDB不同于传统的关系型数据库,是由key和value存储的NoSQL数据库,集合了Dom Storgage和Web SQL Database存的优点, 原理: 属于 NoSQL 数据库,通过存储字符串的 Key - Value 对来提供 特点:
- 功能强大,使用简单
- 存储空间大
- 使用灵活,可以存储任意类型的值或对象
应用场景: 存储 复杂、数据量大的结构化数据 客户端实现: WebSettings settings = getSettings(); // 只需设置支持JS就自动打开IndexedDB存储机制 // Android 在4.4开始加入对 IndexedDB 的支持,只需打开允许 JS 执行的开关就好了。 settings.setJavaScriptEnabled(true);
4、Application Cache(AppCache)机制 原理: 以文件为单位进行缓存,且文件有一定更新机制(类似于浏览器缓存机制),AppCache已经不推荐使用了,标准也不会再支持 AppCache 原理有两个关键点:manifest 属性和 manifest 文件。 // HTML 在头中通过 manifest 属性引用 manifest 文件 // manifest 文件:就是上面以 appcache 结尾的文件,是一个普通文件文件,列出了需要缓存的文件 // 浏览器在首次加载 HTML 文件时,会解析 manifest 属性,并读取 manifest 文件,获取 Section:CACHE MANIFEST 下要缓存的文件列表,再对文件缓存
AppCache 在首次加载生成后,也有更新机制。被缓存的文件如果要更新,需要更新 manifest 文件 因为浏览器在下次加载时,除了会默认使用缓存外,还会在后台检查 manifest 文件有没有修改(byte by byte) 发现有修改,就会重新获取 manifest 文件,对 Section:CACHE MANIFEST 下文件列表检查更新manifest 文件与缓存文件的检查更新也遵守浏览器缓存机制 如用户手动清了 AppCache 缓存,下次加载时,浏览器会重新生成缓存,也可算是一种缓存的更新 AppCache 的缓存文件,与浏览器的缓存文件分开存储的,因为 AppCache 在本地有 5MB(分 HOST)的空间限制 特点:
- 方便构建Web App的缓存,专门为 Web App离线使用而开发的缓存机制
应用场景: 存储静态文件(如JS、CSS、字体文件),应用场景同浏览器缓存机制,但AppCache 是对 浏览器缓存机制 的补充,不是替代。 客户端实现:
WebSettings settings = getSettings();
String cacheDirPath = context.getFilesDir().getAbsolutePath()+"cache/";
settings.setAppCachePath(cacheDirPath);
settings.setAppCacheMaxSize(20*1024*1024);
settings.setAppCacheEnabled(true);
5、File System 缓存机制 File System是 H5 新加入的缓存机制,所以Android WebView暂时不支持 原理: 它为Web App提供了一个运行在沙盒中的虚拟的文件系统。不同WebApp的虚拟文件系统是互相隔离的,虚拟文件系统与本地文件系统也是互相隔离的。Web App在虚拟的文件系统中,通过File System API提供的一组文件与文件夹的操作接口进行文件(夹)的创建、读、写、删除、遍历等操作。 浏览器给虚拟文件系统提供了两种类型的存储空间:临时的和持久性的: 临时的存储空间是由浏览器自动分配的,但可能被浏览器回收; 持久性的存储空间需要显示的申请,申请时浏览器会给用户一提示,需要用户进行确认。持久性的存储空间是 WebApp 自己管理,浏览器不会回收,也不会清除内容。存储空间大小通过配额管理,首次申请时会一个初始的配额,配额用完需要再次申请。 特点:
- 可存储数据体积较大的二进制数据
- 可预加载资源文件
- 可直接编辑文件
应用场景: 通过文件系统 管理数据
总结:
浏览器协议缓存和H5应用缓存虽然已满足了大部分使用场景,但仍有明显的不足,比如缓存空间的限制、缓存规则设置复杂等问题,所以在客户端侧很有必要维护一套本地缓存机制,可以用来弥补webview自身缓存的不足和个性化定制缓存规则
|