一、什么是浏览器缓存?
浏览器缓存是一种存储用户访问的网页资源(如HTML页面、图片、JavaScript文件和样式表等)在本地计算机上。
当用户再次访问同一网页时,浏览器可以从本地缓存中读取资源,而不是每次都从服务器重新下载
二、浏览器缓存的优点
减少网络延迟和带宽消耗
减少了服务器的负担,加快网页的加载速度
提高用户的浏览体验
三、缓存在哪儿?
memory cache
不访问服务器,直接读缓存,从内存中读取缓存。
此时的数据是缓存到内存中的,当 kill 进程后,也就是浏览器关闭以后,数据将不存在。但是这种方式只能缓存派生资源
disk cache
不请求网络资源(服务器),直接从磁盘中读取缓存,当 kill 进程时,数据还是存在。
memory 和 disk 的异同?
都属于强缓存,但区别在于,一个是放在内存中(memory)一个是放在磁盘上(disk),所以 memory cache 要比 disk cache 快得多。
但 memory 在浏览器被关闭时会被释放掉,所以当页面再次打开时,就会使用 disk 的缓存。所以就出现了三级缓存的概念。
思考:浏览器如何决定将资源存储在内存还是磁盘中呢?
浏览器会根据资源的类型和大小、浏览器当前状态、缓存策略、浏览器实现和配置以及页面生命周期等因素,智能地决定资源是存储在内存中还是磁盘中,以优化性能和用户体验。
三级缓存原理
- 先去内存(memory)看,如果有,直接加载
- 如果内存没有,则取硬盘(disk)获取,如果有直接加载
- 如果硬盘也没有,那么就进行网络(200)请求
- 加载到的资源缓存到硬盘和内存
四、浏览器缓存分类?
浏览器在向服务器请求资源时,首先判断是否命中强缓存,再判断是否命中协商缓存!
1. 强缓存(Strong Cache)
浏览器根据响应头中的Expires
或Cache-Control
字段判断资源是否过期。如果没有过期,命中强缓存,浏览器直接从缓存中读取资源,不会向服务器发送请求。
Expires
:HTTP/1.0的产物,表示资源过期的绝对时间
,例如 Expires: Thu, 01 Dec 1994 16:00:00 GMT。它是基于服务器时间的,如果客户端和服务器时间不同步,可能会导致缓存失效。Cache-Control
:HTTP/1.1引入,不受本地系统时间的影响,比 Expires 更加灵活,可以设置多种指令来控制缓存,如max-age
指定资源可以缓存的最大时间。no-cache
,no-store
等。例如:Cache-Control: max-age=3600
(单位:秒)。- no-cache:需要进行协商缓存,发送请求到服务器确认是否使用缓存。这个常和 max-age 共同使用。
- no-store:禁止使用缓存,每一次都要重新请求数据。
- public:可以被所有的用户缓存,包括终端用户和 CDN 等中间代理服务器。
- private:只能被终端用户的浏览器缓存,不允许 CDN 等中继缓存服务器对其缓存。
思考:Cache-Control 与 Expires 可以在服务端配置同时启用,哪个优先级更高?
Cache-Control中的 max-age
提供了相对时间控制,更为精确,优先级更高,浏览器将忽略Expires
头,采用max-age
来决定缓存策略。
2. 协商缓存(Negotiation Cache)
当强缓存未命中(资源过期)时,浏览器会向服务器发送请求以验证资源是否更新 。通过Last-Modified
/If-Modified-Since
或ETag
/If-None-Match
头部进行资源验证,判断资源是否被修改。
如果服务器返回 304
状态码,表示资源未修改,浏览器继续从缓存中读取资源;如果资源被修改,服务器会返回新的资源和 200
状态码。
注意
:虽然 Last-Modified 提供了一个好的机制来帮助浏览器确定资源是否已被修改,但它可能不总是能完美地反映内容变化的细微差别,特别是在内容短时间内发生变化然后又恢复的情况下。ETag可能提供更精确的缓存验证机制,因为它能够基于内容本身的唯一标识(如哈希值)来判断资源是否真的发生了变化。
Last-Modified
和If-Modified-Since
:服务器响应请求时通过 Last-Modified 头告知资源最后修改时间。当浏览器再次请求该资源时,会发送 If-Modified-Since 头,其值为之前收到的 Last-Modified。服务器收到 If-Modify-Since 后,根据资源的最后修改时间判断是否命中缓存。 如果服务器上的资源未被修改命中缓存,则返回 304,浏览器从缓存中加载资源。(简言之:上传新资源后 last-Modify 就会改变,请求的时候带的 if-Modify-Since 是上一次的 last-Modify,两者相对比就能判断出需不需要更新资源)ETag
和If-None-Match
:返回的是一个验证码,ETag 是资源的唯一标识符。资源变化都会导致ETag变化。服务器根据浏览器上发送的 If-None-Match 值来判断是否命中缓存。如果ETag未改变,服务器返回304状态码,资源从缓存加载。
思考:Last-Modified 与 ETag 是可以一起使用的,是否也存在优先级呢?
ETag
提供了比Last-Modified
更细粒度的控制,因为它能够检测到资源内容的任何微小变化。因此,尽管HTTP协议没有明确规定两者之间的优先级,但存在ETag
时,服务器和浏览器往往会优先考虑使用ETag
进行缓存验证,验证 ETag一致的情况下,才会继续比对 Last-Modified,最后才决定是否返回 304。
总结
当浏览器再次访问一个已经访问过的资源时,它会这样做:
- 看看是否命中强缓存,如果命中,就直接使用缓存。
- 如果没有命中强缓存,就发请求到服务器检查是否命中协商缓存。
- 如果命中协商缓存,服务器返回 304 告诉浏览器使用本地缓存。
- 否则,返回最新的资源。

缓存策略
为了有效地利用缓存,开发者需要根据资源的更新频率和重要性来设置合适的缓存策略。通常,不变的资源(如库文件)可以设置较长的缓存时间,而频繁更新的资源(如用户个人信息)应该禁止或设置短暂的缓存。
用户控制
用户也可以手动清除浏览器缓存,或通过设置浏览器来禁用缓存。
注意事项
- 虽然缓存可以提高性能,但不合理的缓存策略也可能导致用户看到过时的内容。
- 服务端设置缓存策略时需要谨慎,以确保更新能够及时反映到用户端。
- 浏览器和服务器可能有自己的缓存规则,开发者应该理解并正确配置这些规则。
参考文章: