认识Http的缓存策略

我们日常开发经常和网络打交道,从服务器上面获取数据。但是如果我们如果在短时间内多次向服务器请求的数据其实都是一样的,我们是没有必要这么浪费用户的流量的。为了提高用户的体验,我们需要合理使用缓存,要使用缓存就得搞明白缓存的一些相关策略机制,于是就有了这篇文章。

Http的缓存机制

我们可以先看下面的思维导图来简单了解一下Http协议里面的一些缓存机制:

导图.png

正如上图所示,Http的缓存就仅可用于Get请求。为了方便大家理解上图,这里我简单介绍一下一些缓存相关的重要字段:

Expires:

这个字段是记录着缓存的有效期,如Expires:Wed, 26 Jul 2017 13:18:20 GMT.当客户端发现这个缓存有效期已经过去了,就会重新向服务器请求数据.但是这个字段存在问题,就是客户端本地时间和服务器端时间相差过大,就是出现缓存读取失效的情况.

Cache-Control:

这个字段是在http1.1之后出现了,用于替代Expires字段的作用.如果Cache-Control:max-age=(X)秒和Expires同时存在,那么就会给Cache-Control:max-age(X)秒替代.不过这个字段并没有这么简单,它还有其他重要的字段,我们来看下面的介绍:
<code>[1] max-age:</code>这个上面已经简单介绍了一下,这里再具体说明一下:缓存的内容将在xxx秒后失效,这个选项只在HTTP 1.1可用,优先级比Expires高.简单来说就是判断缓存内容上次访问时间是否比这个max-age要小,小就使用缓存.
<code>[2] no-cache:</code>先不要读取缓存中的文件,向WEB服务器请求验证缓存是否新鲜,新鲜则使用缓存
<code>[3] must-revalidate:</code>作用和相同,但是更为严格.每次请求都校验缓存和服务器源文件,一致就使用缓存,不一致就拿最新
<code>[4] no-store:</code>这个字段很关键,它表示数据不在硬盘中临时保存
<code>[5] only-if-cached:</code>就是在客户端有缓存时就是用客户端的缓存,这个一般都是在无网时使用
<code>[6] max-stale:</code>只要缓存的时间没有超过它(max-stale)指定的时间,就可以加载使用.我们可以在无网络的情况下使用
上面关于<code>no-cache</code>和<code>must-revalidate</code>的内容,我是参考下面这篇文章的:
web性能优化之:no-cache与must-revalidate深入探究

Last-Modified / If-Modified-Since

这是需要有缓存存在才能起作用的字段。
<code>Last-Modified:</code>这个字段是用来标记这个响应资源的最后修改时间。服务器在响应请求时,将会告诉客户端这个响应资源的最后修改时间,如Last-Modified:Thu, 13 Jul 2017 06:31:05 GMT;

<code>If-Modified-Since:</code>当缓存不新鲜时,发现缓存具有Last-Modified声明,服务器就会检查请求头If-Modified-Since(客户端缓存页面数据的最后修改时间),服务器会把这个时间与服务器上实际文件的最后修改时间进行比较。如If-Modified-Since:Mon , 24 Jul 2017 18:53:33 GMT
如果时间一致,那么返回HTTP状态码304,客户端接到之后,就直接把本地缓存文件显示到屏幕上面。
如果时间不一致,就返回HTTP状态码200和新的文件内容,客户端接到之后,会丢弃旧文件,把新文件缓存起来并显示新的内容。

Etag / If-None-Match

这是需要有缓存存在才能起作用的字段,而且<code>Etag</code>的优先级高于<code>Last-Modified</code>
<code>Etag:</code>这个字段是请求变量的实体标记。简单来说就是服务器响应时给请求URL标记,并在HTTP响应头中将其传送到客户端进行存储。服务器端返回的格式如:Etag:“5d8c72a5edda8d6a:3239″.这是通过对文件的索引节(INode)大小(Size)和最后修改时间(MTime)进行Hash后得到的数值;

<code>If-None-Match:</code>上面说了,<code>Etag</code>是服务器的报文才有的,那么客户端需要给服务器发送Etag应该怎么办?
就是在http报文里面使用If-None-Match这个字段来存放Etag的值.服务器收到请求后发现有If-None-Match则与被请求资源的相应校验串进行比对,之后才决定返回200304.如:If-None-Match:"5d8c72a5edda8d6a:3239"

Etag 和 Last-Modified

到这里我们会发现一件事,就是<code>Last-Modified</code>和<code>Etag</code>的功能居然是重复的,这就奇怪了。既然使用<code>Last-Modified</code>已经足以让客户端知道本地的缓存副本是否足够新,为什么还需要<code>Etag</code>呢?其实还是有原因的,因为<code>Last-Modified</code>有下面几个问题难以解决:
1.<code>Last-Modified</code>标注的最后修改只能精确到秒级,如果某些文件在1秒钟以内被修改多次的话,它将不能准确标注文件的修改时间
2.如果某些文件会被定期生成,当有时内容并没有任何变化,但<code>Last-Modified</code>却改变了,导致文件没法使用缓存
3.有可能存在服务器没有准确获取文件修改时间或者与代理服务器时间不一致等情形
<code>Etag</code>是服务器自动生成或者由开发者生成的对应资源在服务器端的唯一标识符,能够更加准确的控制缓存;<code>Last-Modified</code>与<code>ETag</code>是可以一起使用的,服务器会优先验证<code>ETag</code>,一致的情况下,才会继续比对<code>Last-Modified</code>,最后才决定是否返回304200.

通过okhttp的cache设置来加深理解

我们现在已经了解了部分Http的缓存策略,下面我们来通过代码来加深了解吧。本人比较喜欢okhttp,所以下面的代码都是用它来弄了。

public void click(View view) {
        int maxCacheSize = 10 * 1024 * 1024;
        //设置缓存路径
        Cache cache = new Cache(getCacheDir(), maxCacheSize);
        OkHttpClient client = new OkHttpClient.Builder()
                //设置缓存
                .cache(cache)
                .build();
        Request request = new Request.Builder()
                .url("http://www.qq.com/")
                .build();
       
        client.newCall(request).enqueue(new Callback() {

            @Override
            public void onResponse(Call call, Response response) throws IOException {
               Log.w(TAG, "start");
                Log.w(TAG, "response cache :" + response.cacheResponse());
                Log.w(TAG, "response network :" + response.networkResponse());
                response.body().close();
            }
            @Override
            public void onFailure(Call call, IOException e) {

            }
        });
    }

我们先来看下qq官网的Cache-Control:

image.png

可以看到max-age=60,说明本地缓存在60秒内都是新鲜的,那么我们就连续两次访问qq官网来看下Log吧:

image.png

从打印中,我们可以看出第一次访问我们是从服务器中获取最新的数据;但是第二次访问时,就直接使用本地缓存了,毕竟两次请求相隔时间最多才1秒。那么okhttp缓存到本地时,数据是以什么格式保存的呢?这里我是将缓存保存在内部存储里的:

image.png

为了满足好奇心,这里我们来逐一来看下:

7f4c79817fabaeaa0e909754cfe655e7.0里面的内容
7f4c79817fabaeaa0e909754cfe655e7.1里面的内容
journal里面的内容

原来这3个文件分别是请求的header,加密的response和每一条reponse读写操作状态记录。
ok,我们接着来测试,这次换简书的官网来测试,先看下简书官网的一些header信息:

image.png

max-age=0说明缓存有效时间为0秒,但是设置了Etag校验缓存,我们看下请求打印的Log吧:

image.png

我们重点看第二次访问的Log,okhttp的cacheResponse可用,而且它的networkResponse返回的http码为304,说明了本地缓存是可用的。
那么,有什么网站是不支持缓存吗?当然有了,知乎是一个很有名气的网站,它就不支持客户端使用缓存:

image.png

它已经在Cache-Control里面设置不支持硬盘存储的no-store字段了,我们看下运行的Log:

访问知乎的结果

可以看到,我们已经多次重新访问知乎的首页了,但是每次都只能重新向服务器拿最新的数据。

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

推荐阅读更多精彩内容

  • 本文内容大多参考《图解HTTP》一书 一. 认识代理服务器 所以讲缓存为什么要先扯代理服务器?别急,让我们看一下一...
    流光号船长阅读 1,894评论 0 10
  • 浅谈浏览器Http的缓存机制 ✦ ✦ ✦ ✦ ✦ ✦ ✦ ✦ 针对浏览器的http缓存的分析也算是老生常谈了,每隔...
    meng_philip123阅读 996评论 0 10
  • 针对浏览器的http缓存的分析也算是老生常谈了,每隔一段时间就会冒出一篇不错的文章,其原理也是各大公司面试时几乎必...
    全端玩法阅读 872评论 0 9
  • 针对浏览器的http缓存的分析也算是老生常谈了,每隔一段时间就会冒出一篇不错的文章,其原理也是各大公司面试时几乎必...
    单纯的土豆阅读 377评论 0 2
  • 网络特有的延迟以及数据传输的成本,制约互联网快速获取Web资源。为此,HTTP协议引入缓存以空间换时间,使浏览器缓...
    大头8086阅读 3,052评论 2 12