概述
良好的缓存策略可以降低资源的重复加载提高网页的整体加载速度
通常浏览器缓存策略分为两种:强缓存和协商缓存
基本原理
- 浏览器在加载资源时,根据请求头的
Expires
和Cache-Control
判断是否命中强缓存,是则直接从缓存读取资源,不会发请求到服务器。 - 如果没有命中强缓存,浏览器会发送请求到服务器,通过
Last-Modified
和Etag
验证资源是否命中协商缓存,如果命中,服务器返回304 Not Modified
,但是不会返回这个资源的数据,浏览器会从缓存中读取资源。 - 如果前面两者都没有命中,直接从服务器加载资源。
强缓存
强缓存通过 Expires
和 Cache-Control
实现。
Expires
Expires
是 HTTP1.0 的实现,服务端返回 GMT 格式的时间,是资源的实效时间:
Expires: Wed, 11 May 2018 07:20:00 GMT
如果请求时间在此时间之前,则命中强缓存,使用本地资源。
缺点很明显,当服务器与客户端时间偏差较大时,会导致缓存混乱。
Cache-Control
Cache-Control
是 HTTP1.1 的实现,服务端会返回 max-age
相对时间:
Cache-Control: max-age=86400
max-age: 86400
表示该资源的过期时间为 86400s。
Cache-Control
优先级高于 Expires
。也就是同时存在时浏览器会忽略 Expires
协商缓存
当强缓存未命中时,浏览器就会发一个请求到服务器,验证协商缓存是否命中,如果命中,服务器会返回 304 Not Modified 状态。
协商缓存利用的是 Last-Modified/If-Modified-Since
和 Etag/If-None-Match
。
Last-Modified
Last-Modified
是 HTTP1.0 的实现。浏览器第一次请求一个资源的时候,服务器返回的 header
中会加上 Last-Modified
,Last-Modified
是一个时间标识该资源的最后修改时间,例如 Last-Modified: Thu,31 Dec 2037 23:59:59 GMT
。
再次请求该资源时,请求头会加入 If-Modified-Since
,服务器收到请求后会根据资源的最后修改时间判断是否命中缓存。
如果命中,则返回 304 Not Modified
不返回资源内容,不返回 Last-Modified
。
缺点:
- 一些文件也许会周期性的更改,但是他的内容并不改变(仅仅改变的修改时间),这个时候我们并不希望客户端认为这个文件被修改了,而重新 GET;
- 某些文件修改非常频繁,比如在秒以下的时间内进行修改,(比方说 1s 内修改了 N 次),If-Modified-Since 能检查到的粒度是 s 级的,这种修改无法判断(或者说 UNIX 记录 MTIME 只能精确到秒);
- 某些服务器不能精确的得到文件的最后修改时间。
Etag
Etag
是 HTTP1.1 的实现,是资源的唯一表示标识符,当文件内容不发生改变时,Etag
值不变。
请求相同资源时,浏览器会在请求头加入 If-None-Match
值是第一次请求该资源时的 Etag
值。服务器收到请求后判断是否命中缓存。
ETag
的优先级比 Last-Modified
更高。
协商缓存需要配合强缓存使用,如果不启用强缓存的话,协商缓存根本没有意义
其它
Cache-Control 的其它常见值
no-cache
: 跳过强缓存验证阶段,强制发送请求到服务器进行协商缓存验证。资源依然可能被缓存。no-store
: 直接禁止游览器缓存数据,每次用户请求该资源,都会向服务器发送一个请求,每次都会下载完整的资源。public
: 可以被所有的用户缓存,包括终端用户和 CDN 等中间代理服务器。private
: 只能被终端用户的浏览器缓存,不允许 CDN 等中继缓存服务器对其缓存。
memory cache
memory cache 是内存中的缓存,(与之相对 disk cache 就是硬盘上的缓存)。按照操作系统的常理:先读内存,再读硬盘。disk cache 将在后面介绍 (因为它的优先级更低一些),这里先讨论 memory cache。
几乎所有的网络请求资源都会被浏览器自动加入到 memory cache 中。但是也正因为数量很大但是浏览器占用的内存不能无限扩大这样两个因素,memory cache 注定只能是个“短期存储”。常规情况下,浏览器的 TAB 关闭后该次浏览的 memory cache 便告失效 (为了给其他 TAB 腾出位置)。而如果极端情况下 (例如一个页面的缓存就占用了超级多的内存),那可能在 TAB 没关闭之前,排在前面的缓存就已经失效了。
memory cache 机制保证了一个页面中如果有两个相同的请求 (例如两个 src
相同的 <img>
,两个 href
相同的 <link>
)都实际只会被请求最多一次,避免浪费。
disk cache
disk cache 也叫 HTTP cache,顾名思义是存储在硬盘上的缓存,因此它是持久存储的,是实际存在于文件系统中的。而且它允许相同的资源在跨会话,甚至跨站点的情况下使用,例如两个站点都使用了同一张图片。
disk cache 会严格根据 HTTP 头信息中的各类字段来判定哪些资源可以缓存,哪些资源不可以缓存;哪些资源是仍然可用的,哪些资源是过时需要重新请求的。当命中缓存之后,浏览器会从硬盘中读取资源,虽然比起从内存中读取慢了一些,但比起网络请求还是快了不少的。绝大部分的缓存都来自 disk cache。
面试题:请求时浏览器缓存 from memory cache
和 from disk cache
的依据是什么,哪些数据什么时候存放在 Memory Cache 和 Disk Cache 中?
依据: 请求资源命中强缓存。
何时从 memory 取缓存? 何时从 disk 取缓存? 我没能在网上找到标准的答案,以下是个人理解:
- 内存足够的情况下,资源会被缓存到 memory,也就是内存中。页面内再次请求或按 F5 普通刷新的时候会从 memory 中取缓存。
- 关闭浏览器 tab 时,对应的内存资源会被释放。再次打开页面时,若请求的资源命中强缓存,会取磁盘中的缓存,当没有找到对应资源时会向服务端请求资源。
参考文章
本文由 咻咻 创作,采用 知识共享署名4.0
国际许可协议进行许可
本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名
最后编辑时间为: Jun 12,2020