本文部分内容来自: 彻底弄懂 Http 缓存机制 - 基于缓存策略三要素分解法 原创: 李志刚 腾讯Bugly(http://bugly.qq.com)
HTTP 的缓存机制可以分为 3 个部分:
- 缓存存储策略
- 缓存过期策略
- 缓存对比策略
缓存存储策略
用来确定 HTTP 响应内容是否可以被客户端缓存,以及可以被哪些客户端缓存。
这个策略的作用只有一个,用于决定 HTTP 响应内容是否可缓存到客户端
缓存存储策略的主体内容是 Cache-control 这个头部。它的值主要有以下几种:
字段 | 解释 |
---|---|
private | 只有客户端可以缓存 |
public | 客户端和代理服务器都可以缓存 |
max-age | 缓存的过期时间,之后再次请求,如果没有超过缓存失效的时间则可以直接使用缓存 |
no-cache | 需要使用对比缓存来验证缓存数据 |
no-store | 所有内存都不会进行缓存 |
对于其中的 public、private、no-cache、max-age 、no-store 他们都是用来指明响应内容是否可以被客户端存储的,其中前 4 个都会缓存文件数据(关于 no-cache 应理解为「不建议使用本地缓存」,其仍然会缓存数据到本地),后者 no-store 则不会在客户端缓存任何响应数据。另外关于 no-cache 和 max-age 有点特别,我认为它是一种混合体,下面我会讲到。
通过 Cache-Control:public 设置我们可以将 HTTP 响应数据存储到本地,但此时并不意味着后续浏览器会直接从缓存中读取数据并使用,为啥?因为它无法确定本地缓存的数据是否可用(可能已经失效),还必须借助一套鉴别机制来确认才行, 这就是我们下面要讲到的「缓存过期策略」。
缓存过期策略
客户端用来确认存储在本地的缓存数据是否已过期,进而决定是否要发请求到服务端获取数据
这个策略的作用也只有一个,那就是决定客户端是否可直接从本地缓存数据中加载数据并展示(否则就发请求到服务端获取)
刚上面我们已经阐述了数据缓存到了本地后还需要经过判断才能使用,那么浏览器通过什么条件来判断呢? 答案是:Expires,Expires 指明了缓存数据有效的绝对时间,告诉客户端到了这个时间点(比照客户端时间点)后本地缓存就作废了,在这个时间点内客户端可以认为缓存数据有效,可直接从缓存中加载展示。
不过 HTTP 缓存头设计并没有想象的那么规矩,像上面提到的 Cache-Control(这个头是在 Http1.1 里加进来的)头里的 no-cache 和 max-age 就是特例,它们既包含缓存存储策略也包含缓存过期策略,以 max-age 为例,他实际上相当于:
Cache-Control:public/private(这里不太确定具体哪个)
Expires:当前客户端时间 + maxAge 。
而 Cache-Control:no-cache 和 Cache-Control:max-age=0 (单位是秒)相当。
这里需要注意的是:
-
Cache-Control 中指定的缓存过期策略优先级高于 Expires,当它们同时存在的时候,后者会被覆盖掉。
-
缓存数据标记为已过期只是告诉客户端不能再直接从本地读取缓存了,需要再发一次请求到服务器去确认,并不等同于本地缓存数据从此就没用了,有些情况下即使过期了还是会被再次用到,具体下面会讲到。
缓存对比策略
HTTP 的缓存对比策略主要使用的是 ETag。
Etag 是服务端资源的一个标识码。
当客户端发送第一次请求时服务端会下发当前请求资源的标识码 Etag,下次再请求时,客户端则会通过 header 里的 If-None-Match 将这个标识码 Etag 带上,服务端将客户端传来的 Etag 与最新的资源 Etag 做对比,判断客户端缓存数据是否仍有效,如果一样,则表示资源没有更新,本地缓存仍然有效,返回304。
客户端检测到数据过期或浏览器刷新后,往往会重新发起一个 HTTP 请求到服务器,服务器此时并不急于返回数据,而是看请求头有没有带标识( If-Modified-Since、If-None-Match)过来,如果判断标识仍然有效,则返回 304 告诉客户端取本地缓存数据来用即可(这里要注意的是你必须要在首次响应时输出相应的头信息(Last-Modified、ETag)到客户端)。至此我们就明白了上面所说的本地缓存数据即使被认为过期,并不等于数据从此就没用了的道理了。
下面将缓存策略三要素和常用的几个缓存头(项)结合一起,让大家更清晰的认识到它们之间的关系:
PS:作者原文中还结合了两个题目进行说明,特别能够帮助理解
原文地址为:https://mp.weixin.qq.com/s/qOMO0LIdA47j3RjhbCWUEQ
其他参考资料: