一分钟说清浏览器缓存机制

334 阅读7分钟

前言

考虑到 HTTP 缓存是最主要、最具有代表性的缓存策略,也是每一位前端工程师都应该深刻理解掌握的性能优化知识点,我们下面重点针对 HTTP 缓存机制进行剖析。

先说结论

HTTP 缓存分为强缓存协商缓存。优先级较高的是强缓存,在命中强缓存失败的情况下,才会走协商缓存。命中协商缓存,请求会被发送到服务端。此时,并不会返回完整的资源内容。服务器会检查请求头,如 If-Modified-SinceIf-None-Match,这两个值其实就是上一次请求时服务器返回的 Last-ModifiedETag 值。服务器通过比较这些条件来判断资源是否有更新。如果资源没有更新,服务器将返回一个状态码为 304 Not Modified 的响应,这时浏览器会直接从本地缓存中加载资源。如果更新了,那么不走缓存,服务端会返回新的内容。内容其实简单,一定要做到脱口而出的程度。

大纲

1. 缓存位置

  • 浏览器缓存
  • CDN 缓存

2. 缓存对象

  • 页面缓存
  • 资源文件(如图片、CSS、JavaScript等)缓存

3. 缓存策略

  • 强缓存
  • 协商缓存

4. 缓存控制-关键字段

  • Cache-Control
  • Expires
  • Last-Modified
  • Etag

5. HTTP 缓存决策实践建议

缓存位置

浏览器缓存

浏览器缓存是最常见的一种,它将已请求的资源(如页面、图片、CSS、JavaScript等)存储在本地,以便在用户再次访问时能够快速加载。

CDN 缓存

CDN(内容分发网络)缓存位于全球各地的服务器上,可以更快地向用户传递网站内容,减少用户访问服务器的时间,加速页面加载速度。

缓存对象

页面缓存

页面缓存指的是浏览器保存的整个网页内容,包括 HTML、CSS、JavaScript 等文件,使得用户在访问同一页面时无需重新从服务器请求所有内容。

资源文件缓存

资源文件缓存则是针对单个文件(如图片、样式表和脚本文件)的缓存,使得这些文件能够在后续访问中快速加载,减少网络请求次数,提升用户体验。

缓存策略

强制缓存

强制缓存通过 HTTP 头中的 ExpiresCache-Control 字段来控制。当资源命中强缓存时,浏览器直接从本地缓存中获取资源,而不会向服务器发起请求。

对比缓存

当资源未命中强缓存时,浏览器会发送请求到服务器,使用协商缓存机制。服务器会根据 Last-ModifiedETag 等字段来判断资源是否有更新,若无更新则返回 304 状态码,浏览器继续使用本地缓存。

缓存控制-关键字段

Cache-Control (强缓存)

Cache-Control 是 HTTP 头中的关键字段,通过设置 max-ages-maxage 等参数,控制资源的有效期和缓存行为。它的灵活性和优先级比 Expires 更高,适用于大部分的缓存需求。常见用法:

cache-control: max-age=3600, s-maxage=31536000

Expires (强缓存)

Expires 字段是一个时间戳,用来指定资源的过期时间。虽然在 HTTP/1.1 中已逐渐被 Cache-Control 替代,但仍然在某些场景下发挥作用,尤其是对于向后兼容性要求较高的项目。让我们给这个宝宝一个特写:

expires: Thu, Jun 20 2024 16:12:18 GMT

Last-Modified (协商缓存)

Last-Modified 是一个时间戳,如果我们启用了协商缓存,它会在首次请求时随着 Response Headers 返回:

Last-Modified: Thu, Jun 20 2024 06:35:57 GMT

随后我们每次请求时,会带上一个叫 If-Modified-Since 的时间戳字段,它的值正是上一次 response 返回给它的 last-modified 值:

If-Modified-Since: Thu, Jun 20 2017 06:35:57 GMT

Etag(协商缓存)

Etag 是由服务器为每个资源生成的唯一的标识字符串,这个标识字符串是基于文件内容编码的,只要文件内容不同,它们对应的 Etag 就是不同的,反之亦然。因此 Etag 能够精准地感知文件的变化。

Etag和 Last-Modified 类似,当首次请求时,我们会在响应头里获取到一个最初的标识符字符串,举个🌰,它可以是这样的:

ETag: W/"2a3b-1602480f459"

那么下一次请求时,请求头里就会带上一个值相同的,名为 if-None-Match 的字符串供服务端比对了:

If-None-Match: W/"2a3b-1602480f459"

Etag 的生成过程需要服务器额外付出开销,会影响服务端的性能,这是它的弊端。因此启用 Etag 需要我们审时度势。正如我们刚刚所提到的——Etag 并不能替代 Last-Modified,它只能作为 Last-Modified 的补充和强化存在。 Etag 在感知文件变化上比 Last-Modified 更加准确,优先级也更高。当 Etag 和 Last-Modified 同时存在时,以 Etag 为准。

HTTP 缓存决策实践建议

在实际项目中,正确配置和优化 HTTP 缓存是提升网站性能的关键。以下是一些实践建议,帮助你更好地应用和调整缓存策略:

  1. 使用 Cache-Control 替代 Expires

在 HTTP/1.1 中,推荐使用 Cache-Control 头来定义缓存规则,因为它提供了更多的选项和灵活性,例如 max-ages-maxage 等,能够更精确地控制缓存有效期和行为。

  1. 优先考虑强制缓存

对于不经常变化的静态资源,如图片、样式表等,通过设置合理的 max-age 来启用强制缓存,可以显著减少网络请求和加快页面加载速度。

  1. 合理配置协商缓存

对于可能频繁更新的动态内容或需要频繁验证的资源,如 HTML 页面或 API 数据,建议使用协商缓存机制。通过设置 Last-ModifiedETag 来实现资源的条件请求和验证,减少不必要的数据传输和服务器负载。

  1. 理解并利用状态码 304

当资源通过协商缓存验证后,服务器返回 304 状态码,告知浏览器使用本地缓存。这不仅减少了数据传输量,还能加快页面加载速度,提升用户体验。

  1. 考虑 CDN 缓存优化

对于全球用户的网站,使用 CDN 缓存能够有效分发内容,减少网络延迟和服务器负担。合理配置 CDN 缓存策略,如 s-maxagepublic,能够进一步提升访问速度和稳定性。

  1. 使用开发者工具验证和调试

借助浏览器的开发者工具,如 Chrome 的 Network 面板,可以查看和分析每个请求的缓存状态和响应头信息,帮助调整和优化缓存设置。

通过深入理解和应用上述 HTTP 缓存的知识和实践建议,我们可以在项目中有效地提升网站的性能和用户体验。继续学习和探索更多前端性能优化的技巧,将有助于我们在不断变化的互联网环境中保持竞争力和创新性。

期待你在实际项目中成功应用这些技术,创造出更快、更稳定的 Web 应用!