强制缓存这么暴力,为什么不使用协商缓存😡😡😡
前段时间在看面经的时候,发现很多份面经中都被问到了 强缓存
和 协商缓存
。因此我觉得有必要写一篇文章来好好聊聊这两者。
强缓存和协商缓存
浏览器缓存是浏览器在本地磁盘对用户最近请求过的文档进行存储,当访问者再次访问同一页面时,浏览器就可以直接从本地磁盘加载文档,其中浏览器缓存就分为 强缓存
和 协商缓存
:
强缓存
: 当浏览器在请求资源时,根据响应头中的缓存策略信息,判断是否使用本地缓存副本而无需发送请求到服务器。如果资源被标记为强缓存,浏览器会直接从本地缓存中加载资源,而不发送请求到服务器,从而提高页面加载速度并减轻服务器负载;协商缓存
: 协商缓存是一种缓存策略,用于在资源未过期但可能已经发生变化时,通过与服务器进行协商确定是否使用本地缓存。协商缓存通过在请求中发送特定的条件信息,让服务器判断资源是否有更新,并返回相应的状态码和响应头信息,以指示浏览器是否可以使用本地缓存;
所以根据以上所聊到的特点,浏览器缓存有以下几个方面的优点:
- 减少冗余的数据传输;
- 减少服务器负担;
- 加快客户端加载网页的速度;
浏览器会首先获取该资源缓存的 header
信息,然后根据 Cache-Control
和 expires
来判断是否过期。
如图,在浏览器第一次发送请求后,需要再次发送请求时,它会经过以下几个步骤:
- 首先,浏览器发送请求到服务器,请求的资源可能是一个网页、css 文件、JavaScript 文件或者其他类型的文件;
- 当服务器接收到请求后,首先检查请求中的缓存策略,例如请求头中的 Cache-Control 和 expires 字段;
- 如果资源被标记为强缓存,服务器会进行以下判断:如果缓存有效,即资源的过期时间未到达或过期时间在当前时间之后,服务器返回状态码为 200 ok,并在响应头中设置适当的缓存策略,例如设置 Cache-Control 和 Expires 字段,告诉浏览器可以使用本地缓存;如果缓存无效,即资源的过期时间已过或过期时间在当前时间之前,服务器返回新的资源,状态码为 200 ok,并在响应头中设置适当的缓存策略;
- 如果资源未被标记为强缓存或缓存验证失败,服务器进行协商缓存的判断:如果请求头中包含 If-Modified-Since 字段,表示浏览器之前缓存了该组员并记录了最后修改时间,服务器会根据资源的最后修改时间进行判断; 如果资源的最后修改时间与 If-Modified-Since 字段的值相同或更早,服务器返回状态码 304 Not Modified,并在响应头中清除实际的响应头;如果资源的最后修改时间晚于 If-Modified-Since 字段的值,表示资源已经发生了变化,服务器返回新的资源,状态码为 200 ok,并在响应头中设置新的最后修改时间;如果请求头中包含 If-None-Match 字段,表示浏览器之前缓存了该资源并记录资源的 ETag 值,服务器会根据资源的 ETag 进行判断: 如果资源的 ETag 与 If-None-Match 字段的值相同,服务器返回状态码 304 Not Modified,并在响应头中清除实际的响应体;如果资源的 ETag 与 If-None-Match 字段的值不同,表示资源已经发生了变化,服务器返回新的资源,状态码为 200 OK,并在响应头中设置新的 ETag;
- 浏览器接收到服务器的响应之后,根据状态码和响应头信息进行相应的处理:如果状态码为 200 OK,表示服务器返回了新的资源,浏览器使用新的资源并更新本地缓存;如果状态码为 304 Not Modified,表示资源未发生变化,浏览器使用本地缓存的副本;浏览器根据响应头中的缓存策略进行进一步处理: 如果响应头中包含 Cache-Control 字段,浏览器根据其指令执行缓存策略。例如,如果响应头中的 Cache-Control 包含 no-cache,浏览器将不使用本地缓存,而是向服务器发送请求获得最新的资源;如果响应头中包含 Expires 字段,浏览器将与当前时间比较,判断资源的过期时间。如果过期时间已过,浏览器将不使用本地缓存,而是向服务器发送请求获取最新的资源;如果响应头中包含其他相关的缓存控制字段(如 ETag),浏览器可以根据这些字段进行更精确的缓存控制和验证;
其中,在上面的流程中,又有几个令人难懂的字段,主要有以下几个:
ETag
: 它是通过对比浏览器和服务器资源的特征值来决定是否要发送文件内容,如果一样就只发送304 Not Modified
;Expires
: 设置过期时间,是绝对时间;Last-Modified
: 以时刻作为标识,无法识别一秒内进行多次修改的情况,只要资源修改,无论内容是否发生实质性变化,都会将该资源返回客户端;If-None-Match
: 当客户端发送GET
请求时,如果之前已经键相用资源的请求时,并且服务器返回了ETag
,那么客户端可以将ETag
的值添加到If-None-Match
头中,当再次请求该资源时,客户端会将If-None-Match
头发送给服务器,服务器收到请求之后,会检查If-None-Match
投中的值是否与当前资源的ETag
值匹配: 如果匹配,则表示客户端所请求的资源没有发生变化,服务器会返回状态码 304 Not Modified,并且不返回实际的资源内容;如果 If-None-Match 头中的值与服务器上资源的 ETag 值不匹配,说明资源发生了变化,服务器会正常返回资源,并返回状态码 200 OK;
图解强缓存和协商缓存
在上面的内容中讲了这么多的理论, 你是否还是不太理解什么是 强缓存
和 协商缓存
啊,那么接下来我们就用几张图片来弄清楚这两者的区别。
强缓存
强缓存就是文件直接从本地缓存中获取,不需要发送请求。
首次请求
当浏览器发送初次请求时,浏览器会向服务器发起请求,服务器接收到浏览器的请求后,返回资源并返回一个 Cache-Control
字段给客户端,在该字段中设置一些缓存相关的信息,例如最大过期时间。
再次请求
在前面的基础上,浏览器再次发送请求,浏览器一节接收到 Cache-Control
的值,那么这个时候浏览器它会首先检查它的 Cache-Control
是否过期,如果没有过期则直接从本地缓存中拉取资源,返回割到客户端,则无需再经过服务器。
缓存失效
强缓存有过期时间,那么就意味着总有一天缓存会失效,如果客户端的 Cache-Control
失效了,那么它就会像首次请求中一样,重新向服务器发起请求,之后服务器会再次返回资源和 Cache-Control
的值。
协商缓存
协商缓存也叫做对比缓存,服务端判断客户端的资源是否和服务端的一样,如果一样则返回 304
,反之返回 200
和最新的资源。
初次请求
如果客户端是第一次向服务器发出请求,则服务器返回资源和对应的资源标识给浏览器,该资源标识就是对当前所返回资源的唯一标识,可以是 ETag
或者是 Last-Modified
。
之后如果浏览器再次发送请求是,浏览器就会带上这个资源表,此时服务端就会通过这个资源标识,可以判断出浏览器的资源跟服务器此时的资源是否一致,如果一致则返回 304 Not Modified
,如果不一致,则返回 200
,并返回资源以及新的资源标识。
不同刷新操作方式,对强制缓存和协商缓存的影响
不同的刷新操作方式对于强制缓存和写上缓存的影响如下:
- 普通刷新(F5 或 刷新按钮):强制缓存的影响: 浏览器忽略强制缓存,直接向服务器发送请求,获取最新的资源,也就是强制缓存失效;协商缓存的影响: 浏览器放带有缓存验证的字段的请求,浏览器会根据验证结果返回新的资源或者 304 Not Modified;
- 强制刷新(Ctrl+F5 或 Shift+刷新按钮):强制缓存的影响: 同上,强制缓存失效;协商缓存的影响: 浏览器发送不带缓存验证字段的请求,服务器返回新的资源,不进行验证,也就是协商缓存失效;
- 禁用缓存刷新(DevTools 中的 Disable cache 或 Network 勾选 Disable cache):强制缓存的影响: 同上,强制缓存失效;协商缓存的影响: 浏览器会发送带有缓存验证字段的请求,服务器会根据验证结果返回新的资源或 304 Not Modified;
这玩意也就图一乐,一般出现了问题我都是直接重启......
总结
总的来说,强制缓存是通过在请求中添加缓存策略,判断缓存是否有效,避免发送请求到服务器。而协商缓存是通过条件请求与服务器进行通信,验证缓存是否仍然有效,并在服务器返回适当的响应状态码和缓存策略。
强制缓存可以减少对服务器的请求,加快资源加载速度,但可能无法获取到最新的资源。协商缓存能够验证资源的有效性,并在需要时获取最新的资源,但会增加对服务器的请求。选择使用哪种缓存策略取决于具体的应用场景和资源的特性。