「从强缓存到协商缓存:前端浏览器缓存机制详解」

717 阅读3分钟

前端浏览器缓存是指浏览器在第一次请求网页资源时,将资源缓存到本地,以后请求相同的资源时,直接从缓存中读取,而不再向服务器发送请求,从而提高页面加载速度和减轻服务器负担的一种机制。

浏览器缓存分为两种:强缓存和协商缓存。

强缓存

强缓存是指浏览器在第一次请求资源时,服务器返回的响应头中会带有 Cache-ControlExpires 字段,用来标记资源的有效期。如果资源的有效期在当前时间之前,浏览器就直接从缓存中读取,而不再向服务器发送请求。

Cache-Control 字段包含多个值,其中比较常见的有:

  • max-age=<seconds>:缓存的有效期,单位是秒。
  • no-cache:缓存但需要重新验证,每次请求时都会向服务器发送请求。
  • no-store:不缓存任何内容,每次都从服务器获取最新的资源。

Expires 字段指定了一个绝对时间,即资源过期的时间。当浏览器的时间在 Expires 的时间之前时,就会从缓存中读取资源。不过由于 Expires 字段是服务器返回的一个绝对时间,因此对于服务器和客户端的时间差会产生影响,所以在 HTTP/1.1 中已经逐渐被 Cache-Control 取代。

协商缓存

协商缓存是指浏览器在第一次请求资源时,服务器返回的响应头中带有 Last-ModifiedETag 字段,用来标记资源的最后修改时间或者唯一标识符。当浏览器再次请求该资源时,会带上 If-Modified-SinceIf-None-Match 字段,向服务器询问该资源是否发生了变化。如果服务器返回状态码 304 Not Modified,表示资源未发生变化,浏览器就直接从缓存中读取,否则浏览器就会重新请求资源。

Last-Modified 字段指定了资源最后修改的时间,而 ETag 字段则是服务器为该资源生成的唯一标识符。如果服务器返回了 ETag 字段,那么浏览器就会优先使用 ETag 来验证资源是否发生了变化。

假设我们有一个静态文件 /static/index.js,第一次请求时服务器返回的响应头如下:

HTTP/1.1 200 OK
Cache-Control: max-age=3600
Last-Modified: Fri, 05 May 2023 06:00:00 GMT
ETag: "abcde12345"

这表示资源可以被缓存 1 小时,最后修改时间为 2023 年 5 月 5 日 6 点,ETag 为 "abcde12345"。

当浏览器再次请求该资源时,请求头中会带上 If-Modified-SinceIf-None-Match 字段:

GET /static/index.js HTTP/1.1
Host: example.com
If-Modified-Since: Fri, 05 May 2023 06:00:00 GMT
If-None-Match: "abcde12345"

服务器会检查资源是否发生了变化。如果资源未发生变化,服务器会返回 304 Not Modified 状态码,响应头中不会包含资源的内容,浏览器会直接从缓存中读取资源。如果资源发生了变化,服务器会返回新的资源内容,浏览器会更新缓存,并重新渲染页面。

需要注意的是,强缓存和协商缓存并不是互斥的,而是可以同时使用。当浏览器同时使用了强缓存和协商缓存时,会优先使用强缓存。只有在强缓存失效后,才会使用协商缓存。

浏览器缓存机制在 web 应用开发中非常重要,它可以有效地减少服务器的负担,提高用户体验。但是在一些情况下,缓存会导致应用出现问题,比如缓存过期导致用户看到的不是最新的内容,或者缓存内容过多导致浏览器性能下降。因此,在开发 web 应用时,需要合理地使用缓存机制,避免出现这些问题。