从WebView缓存聊到Http 的缓存机制 | 掘金技术征文

版权声明:web

本帐号发布文章均来自公众号,承香墨影(cxmyDev),版权归承香墨影全部。浏览器

未经容许,不得转载。缓存

1、前言

在 Android 开发中,若是用过 WebView 来加载一个网页,老是逃不过 WebView 的缓存策略的设定。WebView 自己也提供了多种缓存的策略来供开发者使用,而有一些涉及到 Http 协议,因此将两个概念集中整理一块儿讲解,但愿对你们有帮助。服务器

2、WebView 缓存策略

WebView 自己是提供了设置缓存策略的 API 的,可使用 WebSetting 对象进行设置。网络

而 WebSetting 中,能够设置多种缓存策略,以下:post

  • LOAD_CACHE_ONLY:不使用网络,只读本地缓存。
  • LOAD_NORMAL:在 API Level 17 中已经被废弃,而在API Level 11 开始,策略如 LOAD_DEFALT。
  • LOAD_NO_CACHE:不使用缓存,只从网络获取数据。
  • LOAD_CACHE_ELSE_NETWORK:只要本地有缓存,就从缓存中读取数据。
  • LOAD_DEFAULT:根据 Http 协议,决定是否从网络获取数据。

LOAD_CACHE_ONLY 和 LOAD_NO_CACHE 都是比较极端的状况,通常咱们也不会使用。LOAD_NORMAL 已经被废弃了,也没什么好说的,而 LOAD_CACHE_ELSE_NETWORK 自己已经决定了策略,只要本地有,就不会从新获取,也不会有什么能够变化的。测试

LOAD_DEFAULT 才是咱们项目上比较经常使用测策略,本文主要对 LOAD_DEFAULT 模式进行讲解,自己它也是 WebView 的默认模式。可是实际开发中,最好仍是显式设定一下,不少 ROM 均可能会修改这部分代码的,我在乐视手机上作过测试,它的默认策略就是 LOAD_CACHE_ELSE_NETWORK 。3d

先来看看 LOAD_DEFAULT 的 API。code

能够看到,它是默认策略,若是不设定强制策略,在资源没有过时的时候,从缓存获取,若是资源过时了,则从网络获取。cdn

这样的一个策略,就和 Http 缓存相关了,由协议来肯定资源加载的策略。

3、Http缓存策略

既然知道 WebView 也是遵循 Http 的缓存策略的,那么咱们就先来看看 Http 缓存的策略是怎么样的。

用 Charles 抓一个包,看看一个常规的静态文件。

能够看到,一个请求的响应头中,包含了不少信息,而其中有一部分是和缓存相关的,下面咱们来一一讲解。

一、Cache-Control

Cache-Control 是 Http 1.1 中新增长的一个用来定义缓存时间的头。若是使用了 Cache-Control 的话,会覆盖掉 Http 1.0 中的一些,例如:Pragma、Expires等,以 Cache-Control 为准。

Cache-Control 也是一个通用的 Http 报文头字段,它能够分别在请求报文和响应报文中使用,而它做为不一样的使用方式,存在不一样的含义。

Cache-Control 的规范写法:

Cache-Control:cache-directive

cache-directive 的可选值有不少,no-cache、no-store、only-if-cached 等,有兴趣的能够自行查查 Http 协议中的定义。可是通常而言,如上图所示,会使用 max-age 来设定一个最大的有效时间的方式来使用,max-age 设定的时间,单位为秒(s)。

Cache-Control 的 max-age 出如今请求报文头和响应报文头中,含义是不同的。

  • 请求头:告知服务器客户端但愿接收一个存在时间(Age)不大于 max-age 的资源。
  • 响应头:告知客户端,该资源在 max-age 设定的时间内是新鲜的,无需再向服务器发送请求了。

WebView 中,若是被设定为 LOAD_DEFAULT 的话,是遵循此规则的,也就是说,当请求资源回来以后,会根据 max-age 设定当前资源的过时时间,在这个时间范围内,则不会从新请求,会直接从缓存中读取资源,而上面的例子中,max-age 被设定为 40000,差很少 11 个多小时。

二、数据新鲜度校验

Cache-Control 这个报文头,决定了客户端是否须要向服务器发送请求。可是,若是已通过期(超过 max-age 设定的时间),当这个请求发送到服务器以后,是否须要服务器返回一个完整的数据呢?

虽然咱们设定了 max-age ,可是它只能表示一个合理的变化频度,也就是说,可能超过这个 max-age 设定的时间,可是请求的文件也并无变化。那么服务器只须要告知客户端,文件没变化,你仍是读缓存的资源就行了。

这个策略,就是使用 ETag 和 Last-Modified 来校验的。当客户端经过 max-age 判断发现请求的资源文件已经再也不新鲜了,须要从服务器上从新获取,在向服务器发送请求的时候,就会经过这些值告知服务器本地缓存资源的一个标识,服务器就经过这个标识来判断客户端缓存的资源是否依然新鲜。

能够看到,当 max-age 失效以后,发送的请求,会携带 if-None-Match 和 if-Modified-Since 这两个报文头,服务器就是根据这两个报文头来断定客户端的资源是否过时,若是过时,则返回新的资源,若是未过时,则返回一个状态码304的一个响应,告知客户端能够继续读取缓存使用。

细心的应该能够看到,请求头里的 if-None-Match 就是以前响应头里的 ETag ,而 if-Modified-Since 就是以前响应头里的 Last-Modified。

下面看看他们的含义:

  • ETag:资源的惟一匹配标识信息。
  • Last-Modified:资源的最后一次修改时间。
  • if-None-Match:比较 ETag 是否不一致。
  • If-Modified-Since:比较资源最后更新的时间是否一致。

固然,对于请求头,还有其余的规则,例如:if-Match、if-Unmodified-Since 等,这个就看服务器的和客户端的实现了。

这里的 ETag 和 Last-Modified 其实能够分开使用,可是若是被同时使用,则要求服务器对这两个值都进行校验,都校验经过了才会返回 304。

那么这么作,有什么好处,实际是全部的缓存策略,都是为了减少各类地方的压力。对于客户端而言,减小了网络请求的压力,对于服务器而言,也减少了请求和流量的压力。

能够看到,一个完整的资源请求,须要 24kb,而当资源没有过时的时候,只须要 1kb 左右便可,而且响应的时间也更快了。

4、例外状况

到这里,对于 WebView 的各个缓存策略的理解应该就明确了。若是使用 LOAD_DEFAULT 则依赖 Http 的缓存策略,而Http 缓存又是依赖 Cache-Control、ETag、Last-Modified 等值来肯定的。

那么,若是咱们将 CacheMode 设定为 LOAD_DEFAULT ,而且给出了一个 max-age = 40000 资源响应头,在不清理缓存的状况下,咱们的 WebView 就不会对该继续发送请求?这样咱们不当心设定了一个极大的 max-age 值,是否客户端的资源好久才会被更新?

其实并非绝对的,在 WebView 中,加载网页,咱们通常使用 loadUrl() 方法,当使用 loadUrl() 方法的时候,它会彻底遵循上面给出的缓存策略,在没有过时的时候去从缓存中读取资源。

可是浏览器在 Http 缓存策略以外,还提供了强制刷新的策略,这样也保证了在某些状况下,能够去服务器是从新获取资源。而这个策略反应在 WebView 中,就是使用 reload() 方法。当使用 reload() 方法的时候,WebView 会从新请求资源,并在报文头中,修改 max-age 为 0 。这样既能够保证当前刷新了会有一个真实的网络请求,又能保证在缓存资源不过时的状况下,不给服务器形成压力。

5、小结

Http 的缓存策略,在 Android 开发中,并非只用在 WebView 上,一些网络库,例如 OkHttp,也是依赖 Http 缓存策略来进行缓存数据的。

本文参加掘金技术征文:juejin.im/post/58d8e9…

公众号二维码.jpg
相关文章
相关标签/搜索