HTTP 缓存分为强缓存和协商缓存.
HTTP 缓存控制机制
- HTML Meta 标记
<META HTTP-EQUIV="Pragma" CONTENT="no-cache">
// 当前页面不缓存, 每次访问都去服务器拉取. 只有部分浏览器支持.
- HTTP 头信息
HTTP 头信息
强缓存 (200 from cache)
判断的字段: expire 或 cache-control
- expire [http 1.0 的标准], 存储的是过期的具体时间
- cache-control [http 1.1 的标准] max-age 值是过期的秒. max-age 最大值不能超过1年. 秒为单位. 优先级高, 以它的结果为准.
由于具体时间没有转换到正确的时区有可能造成错误. 所以倾向于使用 cache-control: max-age
如果强缓存没有命中的话, 则进入协商缓存
协商缓存 (304 or 200)
判断的字段: last-modified 或 Etag
last-modified/If-Modified-Since
- 浏览器第一次请求数据之后,服务端在 Response Headers 会带上 Last-modified (服务端资源最后修改时间).
- 再次请求时, 请求头会带上 If-Modified-Since 去跟服务器资源的最后修改时间对比. 如果修改, 返回 200 , 否则返回 304 .
Etag/If-None-Match
- 第一次请求数据的时候, Response Headers 带上 ETag . (Etag 由服务端生成一段 hash 字段)
- 之后的请求带上 If-None-Match: 原Etag 的值.
last-modified 和 Etag 区别
- 有些服务无法精确的得到资源最后修改时间.
- last-modified 只能精确到秒.
- 一些资源的最后修改时间改变了,但是内容没改变,使用 Last-modified 看不出内容没有改变。
- Etag 的精度比 Last-modified 高,属于强验证. 优先级高
last-modified 和 Etag 优先级
先判断 Etag, 再判断 last-modified. 但是结果会由服务器决策.
一张图总结流程:
Service Worker 缓存
浏览器的请求过程
我们可以在 Chrome 的开发者工具中,Network -> Size 一列看到一个请求最终的处理方式:如果是大小 (多少 K, 多少 M 等) 就表示是网络请求,否则会列出 from memory cache, from disk cache 和 from ServiceWorker。一个请求在查找资源的过程中经过的缓存顺序
- Service Worker、
- Memory Cache(内存)
- 像一些 prefetch 资源也会暂存在内存中.
- HTTP Cache/Disk Cache (硬盘上的缓存)
- Push Cache
一般资源会存入内存. 如果内存不够, 会释放一些.
- 首次请求
走网络请求
- 再次请求 (F5)
三个请求都来自 memory cache。因为我们没有关闭 TAB,所以浏览器把缓存的应用加到了 memory cache。(耗时 0ms,也就是 1ms 以内)
- 关闭 TAB,打开新 TAB 并再次请求
因为关闭了 TAB,memory cache 也随之清空。但是 disk cache 是持久的,于是所有资源来自 disk cache。(大约耗时 3ms,因为文件有点小) 而且对比 2 和 3,很明显看到 memory cache 还是比 disk cache 快得多的。
用户行为与浏览器缓存
- F5 刷新, 内存不见, 协商缓存依然存在
- 强制刷新/控制台强制清除缓存 内存不见, 协商缓存也存在
- 地址栏访问, 回车, 前进后退. 缓存都不在.
缓存日常实践
- 永久缓存: 带 hash 值的静态 js, css资源永久缓存. cache-control : max-age=3153600 一年过期时间
- 对 index.html 使用 Cache-Control: no-cache
幸运的是,关于协商缓存你无需管理,无需配置, nginx 或者一些 OSS 都会自动配置协商缓存,而对于协商缓存,也有它们自己的算法。协商缓存背后是基于 Last-Modified/ETag。浏览器每次请求资源时,会携带上次服务器响应的 ETag/Last-Modified 作为标志,与服务端此时的 ETag/Last-Modified 作比较,来判断内容更改。
关注「前端加加」, 第一时间获取优质文章.