[故事] 浏览器缓存原理你真的懂吗?一篇漫画故事带你理解透顶!


本文知识结构:


今天二毛下了个晚班,坐在异乡寥寥无几人的地铁上,一种“他乡安置不了灵魂,故乡放置不了肉身”的感觉袭来,心情有些许低落。

他似玩非玩着手机,突然被几条信息吸引了注意力:“热干面回来了”、“全国绝大部分省宣布开学了”…

二毛突然心情释怀,想起一句话:冬天已经过去,春天还会远吗?一切都在慢慢变好,包括自己。

回到出租屋,二毛突然看到二丫一脸生气的样子经过,于是凑上前去关心慰问。

1 HTTP协议的组成部分

开始之前,首先我们需要大概了解下 HTTP 协议传输信息的两个组成部分:请求和响应。

1.1 请求

分为:请求行,请求头,请求体。

当客户端向服务端发起请求时,内容层次如下:

其中请求体是服务器真正要接收处理的用户数据;请求行和请求头的一些参数值,主要是用于告诉服务器如何处理这次请求,比如:

  • 根据content-length的值,服务器就知道请求体的长度

  • 根据host的值,服务器就知道要将请求转发给哪个虚拟主机

  • ……

1.2 响应

分为:响应行,响应头,响应体。

当服务端响应资源给客户端时,内容类别如下:

其中响应体是真正展示给用户的内容(一般是html,交给浏览器渲染);响应行和响应头的一些参数值,主要告诉浏览器如何展示响应体的内容,比如:

  • 根据content-type的值,浏览器就知道是将这些内容按图片格式展示,还是以文本方式形式

  • 根据content-length的值,浏览器就知道响应内容的长度

  • ……

1.3 缓存相关的参数

我们主要挑缓存相关的参数来讲:状态码,头部字段。

1.3.1 状态码

这里指的就是服务端的响应状态码,状态码主要分为以下五种:

其中,重要的缓存相关状态码如下:

200 OK: 代表资源被浏览器成功接收,或资源直接从本地获取成功。

304 Not Modified:代表服务端允许请求访问资源,但访问资源未满足条件,不需要将资源响应返回给客户端。

1.3.2 头部字段

认真阅读的朋友们可能会发觉到,上面请求头和响应头的参数怎么有些是一样的(上文的content-type)。的确,其实请求头和响应头都叫做头部字段。头部字段分为以下四种:

1 请求首部字段(Request Header Fields)

从客户端向服务器端发送请求报文时使用的首部。

2 响应首部字段(Response Header Fields)

从服务器端向客户端返回响应报文时使用的首部。

3 通用首部字段(General Header Fields)

请求报文和响应报文两方都会使用的首部。

4 实体首部字段(Entity Header Fields)

针对请求报文和响应报文的实体部分使用的首部。补充了资源内容更新时间等与实体有关的信息。

关于缓存,我们需要关注这几种头部信息:

  • 请求相关:If-Modified-Since,If-None-Match

  • 响应相关:ETag,Last-Modified,Expires,Cache-Control

2 浏览器缓存类型

正如我前面说到的,浏览器缓存有两种,分别是:强缓存和协商缓存。

2.1 强缓存

定义:

顾名思义,就是浏览器强制使用本地缓存来作为资源展示。

在谷歌浏览器按 F12 之后的 network 选项中可以看出:命中强缓存的请求,会得到200状态码,由于字段是从本地获取的,所以size 字段处会显示 from memory cache 或 from disk cache。

强缓存相关的头部信息:

看响应头部字段:Expires 和 Cache-Control。

Expires: 例如【expires: Sun, 03 May 2020 15:02:48 GMT】,标明了这个资源的过期时间,浏览器下一次请求时会对这个时间进行判断,如果没超过这个时间就会命中强缓存,超过了则没命中并重新发起请求。

Cache-Control: 例如【cache-control: max-age=2592000】,标明了这个资源的过期倒计时,这个倒计时浏览器也会存储下来,浏览器下一次请求时会对倒计时进行判断,如果倒计时未完就会命中强缓存,超过了则反之。

2.2 协商缓存

定义

顾名思义,就是要跟服务器进行协商要不要用缓存。

在谷歌浏览器按 F12 之后的 network 选项中可以看出:命中协商缓存的请求,会得到304状态码,然后浏览器就会从本地缓存中读取资源。

协商缓存相关的头部信息

既然是协商,所以此类的头部信息是成双成对出现的:

  • 请求头的 If-None-Match 与 响应头的 ETag

  • 请求头的 If-Modified-Since 与 响应头的 Last-Modified

ETag和If-None-Match:

Etag是上一次加载资源时,服务器返回的响应头,是对该资源的一种唯一标识,只要资源有变化,Etag就会重新生成。浏览器在下一次加载资源向服务器发送请求时,会将上一次返回的Etag值放到请求头里的If-None-Match字段里,服务器接受到If-None-Match的值后,会拿来跟该资源文件的Etag值做比较,如果相同,则表示资源文件没有发生改变,命中协商缓存。

Last-Modified和If-Modified-Since:

Last-Modified是该资源文件最后一次更改时间,服务器会在响应头里返回,同时浏览器会将这个值保存起来,在下一次发送请求时,放到请求头里的If-Modified-Since里,服务器在接收到后也会做比对,如果相同则命中协商缓存。

举个例子。

响应头:

请求头:

ETag和Last-Modified的作用和用法也是差不多,说一说他们的区别。

1 在精确度上,Etag要优于Last-Modified。Last-Modified的时间单位是秒,如果某个文件在1秒内改变了多次,那么他们的Last-Modified其实并没有体现出来修改,但是Etag每次都会改变确保了精度;如果是负载均衡的服务器,各个服务器生成的Last-Modified也有可能不一致。

2 在性能上,Etag要逊于Last-Modified,毕竟Last-Modified只需要记录时间,而Etag需要服务器通过算法来计算出一个hash值。

3 在优先级上,服务器校验优先考虑Etag。

3 浏览器缓存过程示意图

注意:

  • 两者的共同点是,都是从客户端缓存中读取资源;区别是强缓存不会发请求,协商缓存会发请求。

  • 关于优先级:先判断强缓存,后判断协商缓存。

  • 判断强缓存的时候,如果有 Cache-Control ,则只通过 Cache-Control 来判断是否有强缓存;如果没有这个 Cache-Control 这个字段,** 才拿 ** Expire 字段进行判断。

  • 判断协商缓存的时候,如果有 If-None-Match ,则只通过If-None-Match 来判断是否有协商缓存;如果没有 If-None-Match 这个字段,** 才拿 ** If-Modified-Since。

  • https 也是同样的缓存原理,因为 https 只是在 http 的基础上套了SSL/TLS的加密层,其他不变。

4 针对缓存的一些用户操作

  • 地址栏访问,链接跳转是正常用户行为,将会触发浏览器缓存机制;

  • F5刷新,浏览器会设置max-age=0,跳过强缓存判断,会进行协商缓存判断;

  • ctrl+F5刷新,跳过强缓存和协商缓存,直接从服务器拉取资源。

二丫随即拿出笔记本按了下 ctrl+F5 ,果不其然,网站系统正常更新了图片。

我是二毛,一个在大城市漂泊的程序猿。

我的故事未完待续……


关注公众号《程序员二毛》,后台回复 1024 领取变强秘籍;

本作品采用《CC 协议》,转载必须注明作者和本文链接
二毛
本帖由系统于 4年前 自动加精
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
讨论数量: 31

觉得有用或有趣的扣 1 ,看不懂的扣 2 ,其他的扣yanzhuzi :grin: :grin:

4年前 评论

支持 支持 插画很好 讲的也很好

4年前 评论

你以为我是来学习的?
不 我是来看插画的:laughing:

4年前 评论

@lyxxxh 看着插画,看着看着就把知识学了 :relaxed: :relaxed:

4年前 评论

哈哈哈,我改成产品经理二丫!

4年前 评论

灵魂画手二毛你好,写得棒极了。

  • 啊二毛,你比一毛多一毛~ 啊啊,二毛,你比三少一毛 -----来自灵魂歌手
3年前 评论

@DamonYan 灵魂画手......是本人没错了 :joy: :joy:

3年前 评论
自由与温暖是遥不可及的梦想

我能说 你找个 ui 或者 平面 给你画图吧 你这个 让我 难受

3年前 评论

@自由与温暖是遥不可及的梦想 我工作之余画的,没有绘画基础,纯属个人爱好分享技术。。。。后面有时间会慢慢完善hhhh

3年前 评论

总结:网页刷新用ctrl+F5 :joy:

3年前 评论
Coolest 3年前

1 有趣 一个无处安放灵魂的 逗比没跑了 :smile:

3年前 评论

mark一下

3年前 评论

喜欢这种很有灵气的文章 :+1:

3年前 评论

所以 你什么时候把房东的女儿攻陷,就可以安放你的灵魂了 是不是这逻辑

3年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!