强缓存和协商缓存

缓存,作为我们开发过程中经常碰到的一样东西,相信很多小伙伴和我一样对它熟悉又陌生,各种 expiresEtag 好像都知道,却又好像无法把它讲清楚,所以本篇文章就来总结整理下。

一、缓存

首先,什么是缓存?我的理解,缓存就是一个资源副本。当我们向服务器请求资源后,会根据情况将资源 copy 一份副本存在本地,以方便下次读取。它与本地存储 localStoragecookie 等不同,本地存储更多是数据记录,存储量较小,为了本地操作方便。而缓存更多是为了减少资源请求,多用于存储文件,存储量相对较大。

那缓存有啥用呢?缓存最根本的作用就是减少没必要请求。有些资源,比如用户头像图片,很久才改变一次,但每次都要去请求这张一样的图片,通信一来一回增加了页面的显示时长,过多没必要请求也增加了服务器的压力。如果把这张图片直接缓存在本地,那每次就可以直接本地读取加载,不再发起请求。所以缓存的好处也就显而易见了,减少了时长从而优化用户体验,也减少了流量消耗,减轻了服务器的压力

那么,缓存有哪些呢?就浏览器而言,一般缓存我们分为四类,按浏览器读取优先级顺序依次为:Memory CacheService Worker CacheHTTP CachePush Cache。而本篇文章主要讲的就是 HTTP Cache ,其他有兴趣可以自行搜索。

二、HTTP Cache

HTTP Cache 是我们开发中接触最多的缓存,它分为强缓存和协商缓存。

  1. 强缓存:直接从本地副本比对读取,不去请求服务器,返回的状态码是 200
  2. 协商缓存:会去服务器比对,若没改变才直接读取本地缓存,返回的状态码是 304

(一)、强缓存

强缓存主要包括 expirescache-control

1、expires

expiresHTTP1.0 中定义的缓存字段。当我们请求一个资源,服务器返回时,可以在 Response Headers 中增加 expires 字段表示资源的过期时间。

expires: Thu, 03 Jan 2019 11:43:04 GMT

它是一个时间戳(准确点应该叫格林尼治时间),当客户端再次请求该资源的时候,会把客户端时间与该时间戳进行对比,如果大于该时间戳则已过期,否则直接使用该缓存资源。

但是,有个大问题,发送请求时是使用的客户端时间去对比。一是客户端和服务端时间可能快慢不一致,另一方面是客户端的时间是可以自行修改的(比如浏览器是跟随系统时间的,修改系统时间会影响到),所以不一定满足预期。

2、cache-control

正由于上面说的可能存在的问题,HTTP1.1 新增了 cache-control 字段来解决该问题,所以当 cache-controlexpires 都存在时,cache-control 优先级更高。该字段是一个时间长度,单位秒,表示该资源过了多少秒后失效。当客户端请求资源的时候,发现该资源还在有效时间内则使用该缓存,它不依赖客户端时间cache-control 主要有 max-ages-maxagepublicprivateno-cacheno-store 等值。

cache-control: public, max-age=3600, s-maxage=3600 
  1. max-ages-maxage
    两者是 cache-control 的主要字段,它们是一个数字,表示资源过了多少秒之后变为无效。在浏览器中,max-ages-maxage 都起作用,而且 s-maxage 的优先级高于 max-age。在代理服务器中,只有 s-maxage 起作用。 可以通过设置 max-age 为 0 表示立马过期来向服务器请求资源。

  2. publicprivate
    public 表示该资源可以被所有客户端和代理服务器缓存,而 private 表示该资源仅能客户端缓存。默认值是 private,当设置了 s-maxage 的时候表示允许代理服务器缓存,相当于 public

  3. no-cacheno-store
    no-cache 表示的是不直接询问浏览器缓存情况,而是去向服务器验证当前资源是否更新(即协商缓存)。no-store 则更狠,完全不使用缓存策略,不缓存请求或响应的任何内容,直接向服务器请求最新。由于两者都不考虑缓存情况而是直接与服务器交互,所以当 no-cacheno-store 存在时会直接忽略 max-age 等。

3、pragma

既然讲到了 no-cacheno-store,就顺便把 pragma 也讲了。他的值有 no-cacheno-store,表示意思同 cache-control,优先级高于 cache-controlexpires,即三者同时出现时,先看 pragma -> cache-control -> expires

pragma: no-cache

(二)、协商缓存

上面的 expirescache-control 都会访问本地缓存直接验证看是否过期,如果没过期直接使用本地缓存,并返回 200。但如果设置了 no-cacheno-store 则本地缓存会被忽略,会去请求服务器验证资源是否更新,如果没更新才继续使用本地缓存,此时返回的是 304,这就是协商缓存。协商缓存主要包括 last-modifiedetag

1、last-modified

last-modified 记录资源最后修改的时间。启用后,请求资源之后的响应头会增加一个 last-modified 字段,如下:

last-modified: Thu, 20 Dec 2018 11:36:00 GMT

当再次请求该资源时,请求头中会带有 if-modified-since 字段,值是之前返回的 last-modified 的值,如:if-modified-since:Thu, 20 Dec 2018 11:36:00 GMT。服务端会对比该字段和资源的最后修改时间,若一致则证明没有被修改,告知浏览器可直接使用缓存并返回 304;若不一致则直接返回修改后的资源,并修改 last-modified 为新的值。

last-modified 有以下两个缺点:

  • 只要编辑了,不管内容是否真的有改变,都会以这最后修改的时间作为判断依据,当成新资源返回,从而导致了没必要的请求响应,而这正是缓存本来的作用即避免没必要的请求。
  • 时间的精确度只能到秒,如果在一秒内的修改是检测不到更新的,仍会告知浏览器使用旧的缓存。
2、etag

为了解决 last-modified 上述问题,有了 etagetag 会基于资源的内容编码生成一串唯一的标识字符串,只要内容不同,就会生成不同的 etag。启用 etag 之后,请求资源后的响应返回会增加一个 etag 字段,如下:

etag: "FllOiaIvA1f-ftHGziLgMIMVkVw_"

当再次请求该资源时,请求头会带有 if-none-match 字段,值是之前返回的 etag 值,如:if-none-match:"FllOiaIvA1f-ftHGziLgMIMVkVw_"。服务端会根据该资源当前的内容生成对应的标识字符串和该字段进行对比,若一致则代表未改变可直接使用本地缓存并返回 304;若不一致则返回新的资源(状态码200)并修改返回的 etag 字段为新的值。

可以看出 etaglast-modified 更加精准地感知了变化,所以 etag 优先级也更高。不过从上面也可以看出 etag 存在的问题,就是每次生成标识字符串会增加服务器的开销。所以要如何使用 last-modifiedetag 还需要根据具体需求进行权衡。

三、访问刷新分析

我们将访问和刷新分为以下三种情况:

  • 标签进入、输入url回车进入
  • 按刷新按钮、F5 刷新、网页右键“重新加载”
  • ctrl + F5 强制刷新

假设当前有这么一个 index 页面,返回的响应信息如下:

cache-control: max-age=72000
expires: Tue, 20 Nov 2018 20:41:14 GMT
last-modified: Tue, 20 Nov 2018 00:41:14 GMT
1、标签进入、输入url回车进入

这种情况下会根据实际设计的缓存策略去判断。

  1. 由于该例没有设置 no-cacheno-store,所以默认先走强缓存路线。根据 cache-controlexpires 优先级低)判断缓存是否过期,若没有过期则此时返回 200(from cache)
  2. 若本地缓存已经过期再走协商缓存路线,根据之前的 last-modified 值去与服务器比对,若这个时间之后没有改过则去读取本地缓存,返回 304(not modified)
  3. 否则返回新的资源,状态码 200(ok),并更新返回响应的 last-modified 值。
2、按刷新按钮、F5 刷新、网页右键“重新加载”

这种情况下,实际是浏览器将 cache-controlmax-age 直接设置成了 0,让缓存立即过期,直接走协商缓存路线。发送的请求头如下:

cache-control: max-age=0
if-modified-since: Tue, 20 Nov 2018 00:41:14 GMT
3、ctrl + F5 强制刷新

强制刷新的情况下,浏览器会强行设置 no-cache,强制获取最新的资源,就连 if-modified-since 等其他缓存协议字段都会被吃掉。此时发送的请求头如下:

cache-control: no-cache
pragma: no-cache

参考文章

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

推荐阅读更多精彩内容

  • 网络特有的延迟以及数据传输的成本,制约互联网快速获取Web资源。为此,HTTP协议引入缓存以空间换时间,使浏览器缓...
    大头8086阅读 3,037评论 2 12
  • 今天看奇舞团推了篇文章讲缓存策略的,讲的挺不错,记录一下。 原文地址就在下面。 总结: 缓存分为强缓存和协商缓存...
    NowhereToRun阅读 4,764评论 1 7
  • 本文内容大多参考《图解HTTP》一书 一. 认识代理服务器 所以讲缓存为什么要先扯代理服务器?别急,让我们看一下一...
    流光号船长阅读 1,892评论 0 10
  • 转载:浏览器缓存知识小结及应用 阅读目录 1. 浏览器缓存基本认识 2. 强缓存的原理 3. 强缓存的管理 4. ...
    meng_philip123阅读 1,084评论 4 18
  • 浏览器对于请求资源, 流程如图所示: 可以看到浏览器的缓存机制分为两个部分: 1、当前缓存是否过期? 2、服务器中...
    zhoulujun阅读 1,163评论 0 3