在Web开发中,与HTTP协议打交道是必不可少的!
HTTP协议支持缓存机制,并最终由浏览器实现并使用,我们以此作为关注点,来探究以下两个问题:
- HTTP协议中如何支持缓存?
- 具体的工作流程如何?
概述
HTTP 缓存会存储与请求关联的响应,并将存储的响应复用于后续请求。
复用的优点显而易见:
- 不需要将请求传递到服务器,响应速度快;
- 服务器不需要处理业务逻辑,降低了服务器的负载;
在许多其他文章中,作者常常直接介绍强缓存,协商缓存的工作机制,我觉得这样知识的构建过程不够流畅,因此下文我将基于前面提出的两个问题,由浅入深的进行阐述,如有问题欢迎大家指正!
HTTP协议中如何支持缓存?
一句话回答:在Http协议中,规定了很多HTTP请求报文和响应报文的头信息,而在这些头信息中,有很多字段就是用来支持缓存的,这些字段仅仅是依照HTTP协议的规定来表示当前请求/响应的缓存规则,而浏览器和服务器的HTTP模块则是依据协议规定进行开发的!
既然我们知道了HTTP缓存是通过头字段来告知浏览器/中间服务器如何缓存响应了,那么我们就需要学习相关字段了!
头字段
以下所介绍的都是有关HTTP缓存的头字段;
Expires
- 响应头字段;
- 包含日期/时间,即在此时候之后,响应过期,如果值为无效值,则表示已过期;
- 优先级低于
Cache-Control
字段;
Cache-Control
- 优先级高于
Expires
字段; - 通用消息头字段;
- 可设置多种配置项,主要如下:
max-age=<seconds>
: 由服务器设置,设置该响应的最大缓存时间(单位:s),时间是相对于请求的时间;public
:表明响应可以被任何对象(包括:发送请求的客户端,代理服务器,等等)缓存;private
:表明响应只能被单个用户缓存,不能作为共享缓存(即代理服务器不能缓存它);注意: 如果响应具有Authorization
标头,则不能进行缓存,因为响应一般包含用户私有的令牌/凭证/密码等信息;no-cache
:在使用缓存前询问源头服务器内容是否发生变化,并根据结果选择是否使用缓存;no-store
: 不使用缓存;
- 优先级高于
Last-Modified
:是一个响应 头字段,其中包含源头服务器认定的资源做出修改的日期及时间;当与If-None-Match
一同出现时,它会被忽略掉,除非服务器不支持If-None-Match
。If-Modified-Since
:是一个条件式请求 头字段,服务器只在所请求的资源在给定的日期时间之后对内容进行过修改的情况下才会将资源返回,状态码为200
。如果请求的资源从那时起未经修改,那么返回一个不带有消息主体的304 Not Modified
响应,而在Last-Modified
首部中会带有上次修改时间;- 客户端会将对应资源上次响应的
Last-Modified
值设置为下一次询问时If-Modified-Since
的值;
- 客户端会将对应资源上次响应的
E-Tag
- 响应头字段
- 用于指定该资源的版本,是资源版本标识符
- 服务端通过设置E-Tag来标识资源版本,请求端通常会将接收到的E-Tag值设置为
If-None-Match
的值发往服务端,服务端通过If-None-Match
来判断资源是否更改并类似于If-Modified-Since
一样返回200
或304
If-None-Match: <etag_value>
- 请求头字段
- 作用是携带请求资源的
E-Tag
值;If-None-Match (MDN)
具体的工作流程如何?
在学习了解了HTTP协议中有关缓存的部分头字段后,我们接下来要了解一下Cache-Control
和 E-tag
字段具体的工作流程:
源头服务器设置Cache-Control
流程:
E-tag
使用流程:
事实上,这两个字段的工作流程就引出了两种缓存策略:强缓存、协商缓存,他们可以组合使用,同步起效!
强缓存
强缓存实际上就是不去确认当前这个资源是否更新,仅通过第一次请求该资源时所获得的响应中的Cache-Control
或Expires
字段来确认该资源是否可以重用;
但是如果强缓存判断时资源已经过期了,就会经过协商缓存的步骤!
协商缓存
协商缓存实际上就是当某个资源没有配置强缓存或强缓存过期时,我们需要向服务端验证本地缓存的资源是否可以复用的过程。
- 当强缓存过期后,浏览器会将该请求发往服务端,但是会携带资源对应的
If-None-Match:<etag-value>
或If-Modified-Since
头字段信息 - 服务端首先会验证资源是否可以重用从而进行响应:200代表缓存不可用,304代表未更新,可使用缓存数据;
缓存存储在哪
你可以在开发者工具中的网络页签中看到,有些缓存的请求来自内存(memory cache),而有些请求来自硬盘(disk cache)
缓存的存储与你访问的页面URL相关联,当你第一次请求到一个缓存资源后,他将存储在内存中,此时如果你刷新页面,会发现很多请求的来源都是来自内存的!一旦你关闭了页签,再次重新打开时会发现他们又都大多来自硬盘了!
总结
浏览器对资源进行缓存的依据是由HTTP协议中规定的各个字段所决定的;
强缓存所涉及的字段:
Cache-Control Expires
;- 浏览器会优先判断
Cache-Control
协商缓存所涉及的字段:
If-Modified-Since & Last-Modified
E-Tag & If-None-Match
- 服务端会优先判断
If-None-Match
,如果无该字段才会使用If-Modified-Since
;
浏览器发送请求前会先判断强缓存是否可用, 如果不可用则发送请求询问协商缓存是否可用!