1、缓存机制
1.1 浏览器发送请求前,根据请求头的expires和cache-control判断是否命中(包括是否过期)强缓存策略,如果命中,直接从缓存获取资源,并不会发送请求。如果没有命中,则进入下一步。
1.2 没有命中强缓存规则,浏览器会发送请求,根据请求头的last-modified和etag判断是否命中协商缓存,如果命中,直接从缓存获取资源。如果没有命中,则进入下一步。
1.3 如果前两步都没有命中,则直接从服务端获取资源。
2、强缓存
2.1 强缓存场景
- 第一次请求,不存在缓存结果和缓存标识,直接向服务器发送请求
- 存在缓存标识和缓存结果,但是缓存结果已失效,强制缓存失败,则使用协商缓存
- 存在该缓存结果和缓存标识,且该结果尚未失效,强制缓存生效,直接返回该结果
2.2 强缓存规则
当浏览器向服务器发起请求时,服务器会将缓存规则放入HTTP响应报文的HTTP头中和请求结果一起返回给浏览器,控制强制缓存的字段分别是Expires和Cache-Control,其中Cache-Control优先级比Expires高。
2.2.1 Expires
缓存过期时间,用来指定资源到期的时间,是服务器端的具体的时间点。也就是说,Expires=max-age + 请求时间
,需要和Last-modified
结合使用。Expires
是Web服务器响应消息头字段,在响应http请求时告诉浏览器在过期时间前浏览器可以直接从浏览器缓存取数据,而无需再次请求。
Expires 是 HTTP/1 的产物,受限于本地时间,如果修改了本地时间,可能会造成缓存失效。
2.2.1 Cache-Control
在HTTP/1.1中,Cache-Control是最重要的规则,主要用于控制网页缓存,主要取值为:
- - public:所有内容都将被缓存(客户端和代理服务器都可缓存)
- - private:所有内容只有客户端可以缓存,
Cache-Control
的默认取值 - - no-cache:客户端缓存内容,但是是否使用缓存则需要经过协商缓存来验证决定
- - no-store:所有内容都不会被缓存,即不使用强制缓存,也不使用协商缓存
- - max-age=xxx:缓存内容将在xxx秒后失效
3、协商缓存
协商缓存就是强制缓存失效后,浏览器携带缓存标识向服务器发起请求,由服务器根据缓存标识决定是否使用缓存的过程,主要有以下两种情况:
- 协商缓存生效,返回304和Not Modified
- 协商缓存失效,返回200和请求结果
3.1、Last-Modified和If-Modified-Since
- 浏览器首先发送一个请求,让服务端在responese header 中返回请求的资源上次更新时间,就是last-modified,浏览器会缓存下这个时间。
- 然后浏览器再下次请求中,request header中带上
if-modified-since
:[保存的last-modified的值]
。根据浏览器发送的修改时间和服务端的修改时间进行比对,一致的话代表资源没有改变,服务端返回正文为空的响应,让浏览器中缓存中读取资源,这就大大减小了请求的消耗。 - 由于last-modified依赖的是保存的绝对时间,还是会出现误差的情况:
- 保存的时间是以秒为单位的,1秒内多次修改是无法捕捉到的;
- 各机器读取到的时间不一致,就有出现误差的可能性。为了改善这个问题,提出了使用etag。
3.2、ETag和If-None-Match
etag是http议提供的若干机制中的一种 Web 缓存验证机制,并且允许客户端进行缓存协商。生成etag常用的方法包括对资源内容使用抗碰撞散列函数,使用最近修改的时间戳的哈希值,甚至只是一个版本号。 和last-modified 一样。
- 浏览器会先发送一个请求得到etag的值,然后再下一次请求在request header中带上
if-none-match
:[保存的etag的值]
。 - 通过发送的etag的值和服务端重新生成的etag的值进行比对,如果一致代表资源没有改变,服务端返回正文为空的响应,告诉浏览器从缓存中读取资源。
- 二者对比
- 精确度上:Etag 要优于 Last-Modified
- 优先级上:服务器校验优先考虑 Etag
- 性能上:Etag 要逊于 Last-Modified
4、总结
理解下图即可