浏览器缓存主要分为强缓存、协商缓存、启发式缓存,下面进行详细说明。
当我们首次向服务端发起请求时,由于本地没有缓存结果及标识,所以直接向服务端发起请求,服务器会在响应报文的HTTP头中增加缓存标识,客户端即浏览器会根据缓存标识来决定是否缓存结果,需要缓存则将请求结果和缓存标识存入浏览器缓存。
在每次在发起请求时,都会在浏览器缓存中先检查是否有请求结果以及缓存标识
根据有无请求结果及缓存标识,做以下判断:
- 无缓存结果和缓存标识,走强制缓存失败,直接向服务器发起请求
- 有缓存结果和缓存标识
- 缓存标识在有限期内,强制缓存生效,直接返回缓存结果,此时网络请求显示灰色的200
- 缓存标识已失效,则走协商缓存
强缓存
依赖字段: Expires、Cache-ControlCache-Control
优先于 Expires
Expires
来源:上一次响应过程中,服务器在响应头中返回的字段,过期时间,即资源的有效期,是绝对时间。
使用:浏览器在下次发起同一请求时,会通过Expries来判断该请求在本地的缓存是否过期,如果有效则直接读取,否则进行后续逻辑
弊端:客户端与服务端时间不一致,导致命中不准确
Cache-Control
来源:来源:上一次响应过程中,服务器在响应头中返回的字段。
常见属性:
- max-age:资源有效期,为相对时间,以秒为单位。比如
max-age = 3600
表示资源将在1小时后过期,浏览器在该时间段内直接使用本地缓存,不发起网络请求。 - no-cache:客户端可以缓存资源,每次使用缓存资源前都必须重新验证其有效性。这意味着每次都会发起 HTTP 请求,但当缓存内容仍有效时可以跳过 HTTP 响应体的下载。
- no-store:关闭缓存,即每次请求都不进行缓存是否有效的判断,直接向服务端发起请求。
- public:表明响应可以被任何对象(包括:发送请求的客户端,代理服务器,等等)缓存,即使是通常不可缓存的内容。(例如:1.该响应没有max-age指令或Expires消息头;2. 该响应对应的请求方法是 POST 。)
- private:表明响应只能被单个用户缓存,不能作为共享缓存
- must-revalidate:一旦资源过期(比如已经超过max-age),在成功向原始服务器验证之前,缓存不能用该资源响应后续请求。
- max-age=0, must-revalidate:同no-cache
协商缓存
如果本地没有缓存和缓存失效,则走协商缓存的逻辑,协商缓存必定会向服务端发起请求。
依赖字段:Last-Modified 和 If-Modified-Since、ETag 和 If-None-Match (成对出现),服务端响应字段与客户端请求字段相对应
Last-Modified 和 If-Modified-Since
Last-Modified 服务端响应时返回
If-Modified-Since 客户端请求时携带
服务端在响应头中返回 Last-Modified
字段来表示资源的最后修改时间。当客户端发送请求时,在请求头中携带 If-Modified-Since
字段(值为上次获取资源时服务器返回 Last-Modified
)。服务端接收到请求后,会将 If-Modified-Since
与服务端资源最后修改时间进行比较。如果资源未被修改,响应 304 Not Modified
,告知客户端可以使用本地缓存。否则,响应 200 OK
,返回最新的资源以及Last-Modified
。
ETag 和 If-None-Match
ETag 服务端响应时返回
If-None-Match 客户端请求时携带
ETag是资源的唯一标识,可以是资源的哈希值、版本号等,随着资源内容生成。
服务端在响应头中返回 ETag
字段表示资源的唯一性,通常是一个唯一的字符串。当客户端发送请求时,在请求头中携带 If-None-Match
字段(值为上次获取资源时服务端返回 ETag
)。服务端接收到请求后,会将 If-None-Match
与服务端资源最新资源的标识进行比较。如果标识符相同,响应 304 Not Modified
,告知客户端可以使用本地缓存。否则,响应200 OK
,返回最新的资源以及ETag
。
启发式缓存
启发式缓存是浏览器自己的一种缓存策略,当服务端没有返回缓存标识,或者每次返回相同值的缓存标识时,浏览器会自己计算缓存有效期,在该有效期内,使用类似强缓存的缓存策略,直接从本地读取缓存。具体计算规则为:(new Date() - Last-modified-since) * 10%
区别
- 强缓存不会发起请求;协商缓存至少发起一次请求
- 🎯命中强缓存,Http状态码为
灰色的200
;🎯命中协商缓存,Http状态码为304
使用场景
很明显,浏览器之所以设置缓存肯定是有一些作用的,那么都有哪些使用场景呢?
- 减少页面加载时间
当我们每次进入页面时,都需要从服务端获取css或js文件,然后进行加载、渲染等等会耗费一定的时间,如果能够把公共部分或者没有更新的部分缓存到本地,就可以省去请求耗时 - 资源预加载:在进入某页面时,对于体积较大的网络资源提前加载&缓存
- 待补充…