Http缓存机制及原理
一.前言
Http缓存机制,一向在开发中会作为Web性能优化的重要手段.合理使用浏览器的缓存,可以有效的减少请求访问次数,一是减小服务器压力,更重要的是能降低页面的加载时间
二.缓存中的HTTP报文
这里只介绍与缓存相关的请求报文和响应报文,作为一个知识储备,好为下面介绍缓存做铺垫
HTTP 报文就是浏览器和服务器间通信时发送以及响应的数据块
浏览器向服务器请求数据,发送请求Request报文
服务器向浏览器返回数据,返回响应Response报文
报文主要分为两部分
(1) 包含属性的首部(header) cookie,缓存信息,与缓存相关的规则信息,都包含在header中
(2) 包含数据的主体部分(body) 真正想要传输的部分
三.缓存规则
为了便于理解,认为浏览器存在一个缓存数据库,用于存储缓存信息.
1.第一次请求时缓存规则
客户端第一次请求数据时,此时的缓存数据库中没有对应的缓存数据,需要请求服务器,服务器返回后,将数据存储到缓存数据库中.
2.强缓存规则
已存在缓存数据时,仅基于
强制缓存
,请求数据的流程如下
1.强制缓存规则下,缓存命中:
当客户端请求数据时,先在缓存数据库中检查,是否有缓存数据,当缓存命中时,说明缓存并没有失效,返回数据到客户端
2.强制缓存规则下,缓存未命中
当客户端请求数据时,先在缓存数据库中检查,是否有缓存数据,有,但是缓存未命中,说明缓存数据已经失效了,告诉客户端失效了,然后客户端重新向服务端请求数据,服务器返回数据和缓存规则,客户端接收到了,然后再存进缓存数据库
注意:强缓存是不会向服务器发送请求的,这里是未命中的情况
3.协商缓存规则
已存在缓存数据时,仅基于协商缓存,请求数据流程如下
1.协商缓存规则下,缓存命中
客户端向缓存数据库中获取缓存数据的标识,拿到缓存数据的标识之后,再去请求服务器验证缓存标识对应的数据是否失效
服务器通知客户端缓存未失效,然后客户端再从缓存数据库中获取缓存数据
2.协商缓存规则下,缓存未命中
客户端向缓存数据库中获取缓存数据的标识,拿到缓存数据的标识之后,再去请求服务器验证缓存标识对应的数据是否失效
服务器发现缓存标识对应的数据失效后,返回最新数据和缓存规则,客户端拿到最新的数据和缓存规则,再放入缓存数据库
4.强缓存规则和协商缓存规则区别
从上述的解析中,我们可以看到两类缓存规则的不同:
(1) 强制缓存如果生效,不需要再和服务器发生交互,而协商缓存不管是否生效,都需要与服务端发生交互.
(2) 两类缓存规则可以同时存在,强制缓存优先级高于协商缓存,也就是说,当执行强制缓存的规则时,如果缓存生效,直接使用缓存,不再执行协商缓存规则.
四.强缓存
不会向服务器发送请求,直接从缓存中读取资源,在Chrome控制台的Network选项中可以看到该请求返回200的状态码,并且Size选项显示 from disk cache或 from memory cache.
从上面图解过程中,我们了解到,强制缓存,在缓存数据未失效的情况下,可以直接使用缓存数据,那么浏览器是怎么判断缓存数据是否失效
的呢?
在没有缓存数据时,浏览器向服务器请求数据时,服务器会将数据和缓存规则一并返回,缓存规则信息包含在响应header中
对于强缓存,响应header
中,有两个字段来标识实现规则
- Expires
- Cache-Control
1.Expires
Expires的值为服务端返回的到期时间,也就是下一次请求时,请求时间小于服务端返回的到期时间,可以直接使用缓存数据
但是! Expires
是HTTP 1.0
的内容,现在浏览器默认使用HTTP1.1
,所以它的作用基本可以忽略,还存在另一个问题,到期时间是由服务端生成的,有时候客户端时间可能会跟服务端时间有误差,这就会导致缓存命中的误差,所以HTTP 1.1
的版本,使用Cache-Control
替代
2.Cache-Control
Cache-Control 是最重要的规则,常见的取值有private,public,no-cache,max-age,no-store 默认private
属性 | 描述 |
---|---|
private | 客户端可以缓存 |
public | 客户端和代理服务器都可缓存 |
max-age=xxx秒 | 缓存的内容将在多少秒之后失效 |
no-cache | 需要使用协商缓存 来验证缓存数据 |
no-store | 所有内容都不会缓存,强制缓存,协商缓存都不会触发(基本不使用) |
PS:当Cache-Control与Expires同时存在时,Cache-Control的优先级高于Expires
五.协商缓存(对比缓存)
协商缓存:当强缓存失效后,浏览器携带缓存标识向服务器发起请求,由服务器根据缓存标识决定是否使用缓存.其实就是需要进行比较判断是否可以使用缓存
浏览器第一次请求数据时,服务器会将缓存标识与数据
一起返回给客户端,客户端将二者备份至缓存数据库中,当再次请求数据时,客户端将备份的缓存标识
发送给服务器,服务器根据缓存标识
进行判断,判断命中成功后,返回304状态码
,通知客户端比较成功,可以使用缓存数据.
第一次访问时:
第二次访问时:
通过第一次和第二次访问的对比,非常清楚的发现,当协商缓存生效时,状态码为304,并且报文大小和请求时间大大减少
其背后的原理是:服务端在进行标识比较后,只返回header部分,通过状态码通知客户端使用缓存,不再需要将报文主体部分返回给客户端.
所以说,对于协商缓存,接下来我们将着重的理解这个缓存标识的传递
它在请求header和响应header间进行传递,共分为两种标识传递
Response: Last-Modified/ Request: If-Modified-Since
Reponse: Etag /Request : If-None-Match
1.Last-Modified/If-Modified-Since
服务器在响应请求时,告诉浏览器资源的最后修改时间
Last-Modified:
If-Modified-Since
再次请求服务器时,通过此字段通知服务器上次请求时,服务器返回的资源最后修改时间.
服务器收到请求后发现有If-Modified-Since
,则与被请求资源的最后修改时间进行比对.
- 如果资源的最后修改时间大于
If-Modified-Since
,说明资源被改动过,则响应整个所有资源内容,返回状态码200 - 如果资源的最后修改时间小于或者等于
If-Modified-Since
,说明资源没有新的修改,返回状态码304,告知浏览器继续使用所保存的缓存
2.Etag/If-None-Match
服务器响应请求时,告诉浏览器当前资源在服务器的唯一标识(生成规则由服务器决定),只要资源有变化,Etag就会重新生成.
优先级高于Last-Modified/If-Modified-Since
Etag
第一次请求时,服务器会返回当前资源的唯一标识!
If-None-Match
再次请求服务器时,通过此字段通知服务器客户端缓存数据的唯一标识,服务器收到请求后发现有If-None-Match
则与被请求资源的唯一标识进行比对
- 不同,说明资源被改动过,则响应整片资源内容,返回状态码200
- 相同,说明资源无新修改,则响应
HTTP 304
,告诉浏览器可以继续使用所保存的缓存资源
3.Last-Modified与Etag对比
-
(1) 精确度是上
Etag
要优于Last-Modified
Last-Modified
的时间单位是秒,如果某个文件在1秒内改变了多次,那么他们的Last-Modified
其实并没有体现出来修改,但是Etag
每次都会改变,确保了精确度,如果是负载均衡的服务器,各个服务器生成的Last-Modified
也会可能不一致. -
(2) 性能上,
Etag
要弱于Last-Modified
,毕竟Last-Modified
只需要记录时间,但Etag
需要服务器通过算法来计算一个hash值
-
(3) 优先级上,服务器校验优先考虑
Etag
六.缓存存储位置的状态
在Chrom
浏览器中的控制台Network
中的size
栏,通常会有三种状态
- from memory cache
- from disk cache
- 资源本身的大小(如50B)
1.from memory chche
字面理解是从内存中,这个资源是直接从内存中拿到的,不会请求服务器,一般已经加载过该资源且缓存在了内存当中,当关闭页面时,此资源就会被内存释放掉,再次重新打开相同的页面时,不会出现from memory cache
的情况
2.from disk cache
同上类似,此资源从磁盘中取出的,也就是在此之前的某个时间加载过资源,不会请求服务器,但是此资源不会随着该页面的关闭而释放掉,因为是存在硬盘中的,下次打开仍然会是from disk cache
3.资源本身大小数值
当Http状态为200,是实实在在从浏览器获取的资源,当Http状态码为304时,该数字是与服务端通信报文的大小,并不是该资源本身的大小,该资源是从本地获取的
状态 | 类型 | 说明 |
---|---|---|
200 | form memory cache | 不请求网络资源,资源在内存当中,一般脚本、字体、图片 会存在内存当中。 |
200 | form disk ceche | 不请求网络资源,在磁盘当中,一般非脚本会存在内存当中,如css 等。 |
200 | 资源大小数值 | 资源大小数值 从服务器下载最新资源。 |
304 | 报文大小 | 请求服务端发现资源没有更新,使用本地资源,即命中协商缓存。 |
七.缓存机制总结
对于强缓存,服务器通知浏览器一个缓存时间,在缓存时间内,下次请求,直接用缓存,不在时间内,执行协商缓存策略
对于协商缓存,将缓存信息中的Etag和Last-Modified通过请求发送给服务器,由服务器校验,返回304状态码时,浏览器直接使用缓存.
整个缓存机制如下:
强缓存优先于协商缓存进行,若强缓存(Expires和Cache-Control)生效,则直接使用缓存,若不生效,则进行协商缓存(Last-Modified/If-Modified-Since和Etag/If-None-Match),协商缓存由服务器决定是否使用缓存,若协商缓存失效,那么代表该请求的缓存失效,返回200的状态码,重新返回资源和缓存标识,再存入浏览器缓存中,生效则返回304,继续使用缓存.
1.强缓存和协商缓存区别
缓存类型 | 获取资源形式 | 状态码 | 发送请求到服务器 |
---|---|---|---|
强缓存 | 从缓存取 | 200(from cache) | 否,直接从缓存取 |
协商缓存 | 从缓存取 | 304(Not Modified) | 是,通过服务器来告知缓存是否可用 |
2.用户行为对缓存的影响
用户操作 | Expires/Cache-Control | Last-Modied/Etag | |
---|---|---|---|
地址栏回车 | 有效 | 有效 | |
页面链接跳转 | 有效 | 有效 | |
新开窗口 | 有效 | 有效 | |
前进回退 | 有效 | 有效 | |
F5刷新 | 无效 | 有效 | |
Ctrl+F5强制刷新 | 无效 | 无效 |
3.浏览器请求时序图
当浏览器第一次请求时:
当浏览器再次请求时:
参考文章:
彻底弄懂HTTP缓存机制及原理
浏览器缓存策略