浏览器缓存
浏览器缓存分为强缓存和协商缓存,浏览器刷新页面分为:「重新加载页面」、「硬性加载页面」和「清空缓存并重新加载页面」,此外还有 PWA 和浏览器存储,这些都为浏览器缓存相关的一些知识点,这篇文章会快速提炼出这些要点。
缓存
最佳实践:
- HTML 资源使用协商缓存,保证动态更新,其他资源编译时命名加入 hash
contenthash
并使用强缓存提升资源利用率。 - 新版本发布时,HTML 快速更新并通过
contenthash
指向新的资源,客户端获取新资源并缓存,老缓存不再命中并逐渐过期。
类型 | 控制字段 | 行为 | 说明 |
---|---|---|---|
强缓存 | Expires 、Cache-Control (max-age 、s-max-age 、no-cache 、no-store ) | 命中则直接使用本地缓存,不发请求 | s-max-age 专供中间代理缓存(CDN 等),优先级高于 max-age |
协商缓存 | Last-Modified/If-Modified-Since 、ETag/If-None-Match | 请求时带验证字段,服务器返回 304 或新资源 | 精度:ETag > Last-Modified |
强缓存
-
Expires
:强制约定一个资源过期日日期,在过期前浏览器自动使用该缓存 -
no-cache vs no-store
-
max-age
:浏览器收到资源后能缓存多久,不受系统时间变动影响 -
s-max-age
:CDN 等共享服务器收到资源后能缓存多久 -
no-cache
:资源仍会存本地,但每次使用前都要向服务器确认(简单校验的请求)。 -
no-store
:资源不允许存本地,每次都必须重新请求。
-
协商缓存
Last-Modified/If-Modified-Since
- 请求携带当前缓存资源的最新一次修改的时间,响应返回最近一次修改,两个一致则直接 304 继续使用
- 不一致触发更新
ETag/If-None-Match
:- 分为强弱,强则直接对文件进行 hash 校验,要求每一个字节都一致才能命中缓存
- 弱校验是语义一致,如约定该值为
v1.0.0
,语义一致则命中
缓存过程
- 强缓存过期走协商缓存
- 强缓存配置为
no-cache
走协商缓存 - 强缓存为
no-store
不允许缓存 - 没有强缓存的字段则使用启发缓存,启发缓存过期了才使用协商缓存
- 这些启发式规则通常基于响应头中的
Last-Modified
时间。浏览器会执行如下计算:(CurrentTime - LastModifiedDate) * 0.1
例如,如果一个资源在 100 小时前被修改,浏览器可能会尝试将它缓存100 * 0.1 = 10
小时
- 这些启发式规则通常基于响应头中的
- 协商缓存优先看
Etag
没有再看Last-Modified
- 没有任何缓存字段则不使用缓存
重新加载
刷新方式 | 强缓存 | 协商缓存 | 特点 |
---|---|---|---|
普通刷新 (F5) | 失效 | 可能使用 | 大部分静态资源依旧走协商缓存 |
硬性加载页面 (Ctrl+F5) | 跳过 | 跳过 | 所有资源都向服务器重新请求 |
清空缓存并重载 | 删除缓存 | 全部重新拉取 | 确保获取最新资源 |
硬性加载页面
浏览器在请求头中加上 Cache-Control: no-cache
或 Pragma: no-cache
,强制服务器返回最新资源,同时绕过本地缓存。
特点:在 HTML 内联的资源都会自动添加上这个头部,但在 JS 执行中异步加载的资源不会自动添加头部,可能继续命中缓存
清空缓存并重新加载页面
浏览器清空当前 Host 下的所有缓存,并重新加载资源,此时,所有资源都会重新从服务端获取,并配置缓存
浏览器存储
PWA - Service Worker
拦截网络请求并自定义缓存策略,通过编程更自由的操控缓存提升页面加载速度。通过绕过 HTTP 头部限制可以实现:
- 离线可用
- 自定义缓存优先级
- 后台同步更新
通常只有功能一比较常见,最佳实践是将 Service Worker 视为浏览器缓存网络的一个强大可编程扩展。
对于简单的资源,允许它们“穿过”Service Worker,使用标准的 HTTP 缓存;对于需要特殊处理的资源(如离线所需的核心文件、需要后台更新的API数据),则在 Service Worker 中实现你自己的高级缓存策略。
Cookie、Storage
Cookie
:小容量,用于会话和同源策略的安全设置,客户端和服务端都能写入,只适合存放鉴权相关的敏感信息。localStorage/sessionStorage
:较大容量,用于前端持久化或临时存储。
IndexedDB
浏览器内建数据库,支持结构化数据存储,容量大,适合离线应用,可以配合 ServiceWorker 的 Cache API 使用。
将 Cache API 视为你的 “静态资源仓库”,用于存储应用本身的代码和资源
- Cache API 拦截请求后把资源缓存起来,如 HTML、CSS、JS ,离线通过缓存提供资源。
将 IndexedDB 视为你的 “动态数据库”,用于存储应用产生的结构化数据。
- IndexedDB 存储客户数据,离线后可以实时操作并保存。