浅谈浏览器缓存

354 阅读5分钟

本文主要讲 http 缓存 (资源缓存)

  • 本文讲了缓存的前世今生, 但好像最重要的知识点并没有讲到(就当我不会吧; 好吧 真不会 (´•̥̥̥ω•̥̥̥`) )

缓存的形式

Memory Cache(内存缓存)

  • 时间间隔较短时, 重复请求相同的资源时, 一般情况下资源还在内存中, 那直接从内存中获取资源, 这种方式是最快的资源获取方式
  • 通常情况下, 关闭 tab 页签时, 会清除内存中的资源

Disk Cache(硬盘缓存)

  • 把资源存储到本机的硬盘上, 当再次需要数据时, 可以直接从硬盘上获取
  • 缓存的时间一般会根据请求头的设置而定

CDN 缓存

  • 当用户请求资源时会经过 CDN 服务器, 服务会对可以缓存的资源进行缓存
  • 当有另外的用户也需要这个资源时, CDN 服务器就可以直接返回资源, 不需要再找原服务器要了

服务端缓存

  • 当一些数据需要服务端进行大量计算才能获得时, 服务端为了避免重复的处理影响服务器性能, 开发人员会对处理过的数据进行缓存, 下次再需要时直接取缓存中的数据
  • 服务端缓存一般是一些接口的缓存处理, 我们前端不需要过多关注, 了解即可.
  • 缓存时效可能根据数据的性质不同而不同, 这个不是特别熟这里不做详细讲解

缓存的设置/处理

不对缓存进行设置/处理

  • 这个时候浏览器会根据自己的一套逻辑进行处理
  • 例如: 默认会对 js 资源缓存x天, css 缓存 y 天等

通过 meta 标签设置(不要使用 / 可能已经不生效)

<meta http-equiv="Cache-Control" content="max-age=7200" />
// or 
<meta http-equiv="Cache-Control" content="no-cache" />
  • 虽然说这个可以控制缓存, 但请不要使用, 只需要知道曾经可以这样做即可

设置缓存请求头

缓存优先级: Cache-Control > Expires > Etag > Last-Modified

Last-Modified / If-Modified-Since(缓存校验)

  • Last-Modified(服务端返回): 标记着文件在服务端最后被修改的时间
  • If-Modified-Since(客服端发起): 本地文件的修改时间(可以理解为上次请求返回的 Last-Modified)
  • 当第二次请求数据时, 客户端会带上 If-Modified-Since 请求头, 服务端判断后如果文件没有更改, 直接返回 304 状态码, 请求没有响应体
  • 客户端在收到 304 状态码时, 直接使用本地缓存的资源.
  • 请求过程没有进行数据传递, 效率会高跟多

Etag / If-None-Match(缓存校验)

  • Etag(服务端返回): 请求数据成功后, 返回数据时会携带 Etag 请求头, 他是根据文件生成的一个字符串, 当文件变化时他也会跟着改变

    • 生产算法这个不细讲, 感兴趣的同学可以自行百度.
    • 在进行文件切片上传(大文件上传/断点续传)时也需要生成文件唯一值 应该是类似的, 可以同步关注一下
  • If-None-Match(客服端发起): 上次返回的 Etag 值

整个流程基本上和 (Last-Modified / If-Modified-Since) 很类似

那相比 (Last-Modified / If-Modified-Since) 有什么优势呢?

  1. 如果文件更新(修改时间更新)但是内容没有变, 那使用 Last-Modified 时, 就需要重新请求资源
  2. Last-Modified 返回的时间一般是以秒为单位的, 如果一个文件1秒内更新了多次, 那就会出现问题
  3. 有一些服务器不能精确得到文件的修改时间

Expires(缓存校验)

  • 服务器设置 Expires 字段为一个日期, 客户端请求该资源时将这个日期与客户端当前日期进行比对
  • 如果当前时间小于这个日期, 则表示资源未过期, 使用缓存
  • 如果当前时间大于这个日期, 则表示资源已过期, 客户端就会重新请求该资源

这样做其实存在一个问题: 我们依赖客户端时间, 就会因为客户端的时间不准确导致判断错误

  • 如果客户端时间晚于服务器的时间, 会导致资源还未过期就重新请求
  • 反之, 会导致客户端还在使用过期的旧资源.

Cache-Control

  • Cache-Control 是在 HTTP/1.1 中才有, 算是一个"新"的API (新是相对以前的处理, 因为现在已经有 HTTP3 了)
  • 可选的参数有很多: public, private, no-cache, no-store, max-age= 等
  • 不展开讲了, 可以参考: developer.mozilla.org/zh-CN/docs/…

具体实施(处理方式)

  • 我们一般会使用 nginx 服务器做代理, 通过设置 nginx 配置来设置 Cache-Control 请求头
  • 一般情况下我们会设置 html 文件不做任何缓存 no-store, 其他文件可以设置一个比较长的缓存时间
  • 我们的入口文件一般是 html, 每次上线后更新 html 内的引用即可保证我们的资源引用都是正确的
  • 其他: nginx 还可以实现 gzip 压缩, 感兴趣的自行百度;

总结

  • 缓存形式

    • 内存缓存 => 硬盘缓存 => CDN 缓存 => 服务端缓存
  • 缓存的设置/处理方式

    • 不设置(默认行为) => 设置 meta 标签 => 设置缓存请求头
  • 缓存请求头

    • Last-Modified => Etag => Expires => Cache-Control
  • 有用的知识(你应该学习的知识点, 但没讲 (´•༝•`) ): Cache-Control API

相关文档

前端应该了解的 Nginx 知识
Cache-Control 使用

参考文档

developer.mozilla.org/zh-CN/docs/…

juejin.cn/post/684490…