从WebView缓存聊到Http 的缓存机制

版权声明:

本账号发布文章均来自公众号,承香墨影(cxmyDev),版权归承香墨影所有。

未经允许,不得转载。

一、前言

在 Android 开发中,如果用过 WebView 来加载一个网页,总是逃不过 WebView 的缓存策略的设定。WebView 本身也提供了多种缓存的策略来供开发者使用,而有一些涉及到 Http 协议,所以将两个概念集中整理一起讲解,希望对大家有帮助。

二、WebView 缓存策略

WebView 本身是提供了设置缓存策略的 API 的,可以使用 WebSetting 对象进行设置。

而 WebSetting 中,可以设置多种缓存策略,如下:

  • 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 。

先来看看 LOAD_DEFAULT 的 API。

可以看到,它是默认策略,如果不设定强制策略,在资源没有过期的时候,从缓存获取,如果资源过期了,则从网络获取。

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

三、Http缓存策略

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

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

可以看到,一个请求的响应头中,包含了很多信息,而其中有一部分是和缓存相关的,下面我们来一一讲解。

1、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 个多小时。

2、数据新鲜度校验

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 左右即可,并且响应的时间也更快了。

四、例外情况

到这里,对于 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 。这样既可以保证当前刷新了会有一个真实的网络请求,又能保证在缓存资源不过期的情况下,不给服务器造成压力。

五、小结

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

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

公众号二维码.jpg
公众号二维码.jpg
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,980评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,178评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,868评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,498评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,492评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,521评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,910评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,569评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,793评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,559评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,639评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,342评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,931评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,904评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,144评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,833评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,350评论 2 342

推荐阅读更多精彩内容