目录
浏览器缓存
缓存种类
Service Worker
Memory Cache
preloader
disk cache
添加缓存位置流程
强制缓存 (强缓存)
Expires
Cache-control
协商缓存(对比缓存)
Etag作用
Pragma
协商缓存使用注意
缓存标志优先级
请求流程
浏览器操作对缓存的影响
Ctr F5(硬性重新加载、强制刷新)
Disable cache
Ctr Shift Delete
强缓存假象
缓存案例
浏览器在本地磁盘对用户最近请求过的文档(文件)进行存储(缓存),以便在下一次访问时重复使用,即当访问者再次访问同一页面时,浏览器就可以直接从本地磁盘加载文档,从而节省带宽、提升访问速度、降低服务器压力。
浏览器缓存按位置分类有3种,它们的优先级是:(由上到下寻找,找到即返回;找不到则继续)
我们可以在 Chrome 的开发者工具中F12,Network -> Size 一列看到一个请求最终的处理方式:如果是大小 (多少 K, 多少 M 等) 就表示是网络请求,否则会列出 from memory cache, from disk cache 和 from ServiceWorker。
按缓存方式分类有2种
1.强制缓存(强缓存)
2.协商缓存 (对比缓存)
一种在浏览器后台运行的JavaScript脚本,它可以拦截和处理网页发出的网络请求,以及管理缓存和离线数据。Service Worker可以让网页在离线状态下仍能正常访问,并且可以提高网页的性能和响应速度。它由开发者编写的额外的脚本控制,且缓存位置独立。
Service Worker可以实现以下功能:
如果 Service Worker 没能命中缓存,一般情况会使用 fetch() 方法继续获取资源。这时浏览器就去 memory cache 或者 disk cache 进行下一次找缓存的工作了。经过 Service Worker 的 fetch() 方法获取的资源,即便它并没有命中 Service Worker 缓存,甚至实际走了网络请求,也会标注为 from ServiceWorker。
注意:为了保证安全性,Service Worker只能在HTTPS协议下使用。
内存中的缓存(与之相对 disk cache 就是硬盘上的缓存)。不受开发者控制,也不受 HTTP 协议头的约束,是一个黑盒。
几乎所有的网络请求资源都会被浏览器自动加入到 memory cache 中。但是也正因为数量很大但是浏览器占用的内存不能无限扩大这样两个因素,memory cache 只能是“短期存储”。通常浏览器窗口中的一个页签TAB 关闭后该次浏览的 memory cache 便失效 (为了给其他 TAB 腾出位置)。而如果极端情况下 (例如一个页面的缓存就占用了超级多的内存),那可能在 TAB 没关闭之前,排在前面的缓存就已经失效了。
注意:在从 memory cache 获取缓存内容时,浏览器会忽视例如 max-age=0, no-cache 等头部配置。例如页面上存在几个相同 src 的图片,即便它们可能被设置为不缓存,但依然会从 memory cache 中读取。这是因为 memory cache 只是短期使用,大部分情况生命周期只有一次浏览而已。而 max-age=0 在语义上普遍被解读为“不要在下次浏览时使用”,所以和 memory cache 并不冲突。
如果想让一个资源进入缓存,就连短期也不行,就使用 no-store。存在这个头部配置的话,即便是 memory cache 也不会存储,自然也不会从中读取了。
一种浏览器技术,用于在网页加载过程中预先加载一些资源(如图片、CSS文件、JavaScript文件等),以便在用户访问网页时可以更快地呈现页面内容。Preloader通常使用JavaScript代码来实现,它可以在网页加载时异步加载资源,而不会阻塞页面的渲染(一边解析执行 js/css,一边去请求下一个(或下一批)资源)。
被 preloader 请求够来的资源就会被放入 memory cache 中,供之后的解析执行操作使用。
Web Performance Calendar » Who’s Afraid of the Big Bad Preloader?
disk cache 也叫 HTTP cache(它遵守 HTTP 协议头中的字段,平常说的强制缓存,对比缓存,以及 Cache-Control
等),是存储在硬盘上的缓存,因此它是持久存储的,是实际存在于文件系统中的。而且它允许相同的资源在跨会话,甚至跨站点的情况下使用,例如两个站点都使用了同一张图片。
disk cache 会严格根据 HTTP 头信息中的各类字段来判定哪些资源可以缓存,哪些资源不可以缓存;哪些资源是仍然可用的,哪些资源是过时需要重新请求的。当命中缓存之后,浏览器会从硬盘中读取资源,虽然比起从内存中读取慢了一些,但比起网络请求还是快了不少的。绝大部分的缓存都来自 disk cache。
disk cache同样也会面临空间不足的时候,当 disk cache 空间不足时,会根据 LRU
(Least Recently Used,最近最少使用)算法淘汰掉最近最少使用的缓存数据,腾出空间存储新的缓存数据。LRU 算法的基本思想是,当缓存空间满时,将最近最少使用的缓存数据淘汰掉,腾出空间存储新的缓存数据。具体实现方式是,每次访问缓存数据时,都将该数据移动到链表头部,这样链表尾部的数据就是最近最少使用的数据,可以直接淘汰掉。
当客户端请求后,会先访问缓存数据库看缓存是否存在。如果存在则直接返回;不存在则请求真的服务器,响应后再写入缓存数据库。强制缓存直接减少请求数,是提升最大的缓存策略。
可以造成强制缓存的字段是 Cache-control 和 Expires。
Expires 字段是http1.0时的规范,用于表示资源过期时间的请求头字段,它的值为一个绝对时间的GMT格式的时间字符串,是由服务器端返回的。比如
Expires:Mon,18 Oct 2066 23:59:59 GMT
在响应消息头中,设置这个字段之后代表这个资源在此时间之前命中缓存。
在浏览器第一次请求资源时,服务器端的响应头会附上Expires这个响应字段,当浏览器在下一次请求这个资源时会根据上次的Expires字段是否使用缓存资源(当请求时间小于服务端返回的到期时间,直接使用缓存数据)
注意:expires是根据本地时间来判断的,假设客户端和服务器时间不同,会导致缓存命中误差
为解决expires根据本地时间判断导致缓存命中误差,在http1.1规范中,提出了cache-control字段,且同时使用时优先级高于Expires。
下面是几个常用的属性设置:
完整的属性查看:Cache-Control - HTTP | MDN
协商缓存是由服务器来确定缓存资源是否可用。
客户端与服务器端要通过某种标识来进行通信,从而让服务器判断请求资源是否可以缓存访问,这主要涉及到下面两组header字段,这两组搭档都是成对出现的,
即浏览器第一次发出请求的响应头带上Last-Modified或者Etag字段(若响应头没有Last-Modified或者Etag字段,则请求头也不会有对应的字段)
则后续请求则会带上对应的请求字段If-Modified-Since或者If-None-Match。
当请求头中的 If-Modified-Since、If-None-Match和服务器返回的Last-Modified、Etag分别对应相等时,表示资源没有改变,直接从缓存中取。
HTTP1.1中Etag的出现主要是为了解决几个Last-Modified比较难以解决的问题:
1. 一些文件会周期性的更改,但是他的内容并不改变(仅仅改变的修改时间),这个时候我们并不希望客户端认为这个文件被修改了,而重新GET。
2. 某些文件修改非常频繁,比如在秒以下的时间内进行修改,(比方说1s内修改了N次),If-Modified-Since能检查到的粒度是s级的,这种修改无法判断(或者说UNIX记录MTIME只能精确到秒)。使用 Etag 就能够保证这种需求下客户端在 1 秒内能刷新多次。
3. 某些服务器不能精确的得到(获取)文件的最后修改时间。
Last-Modified与ETag是可以一起使用的,服务器会优先验证ETag,一致的情况下,才会继续比对Last-Modified,最后才决定是否返回304。
Pragma 是一个在 HTTP/1.0 中规定的通用首部,这个首部的效果依赖于不同的实现,所以在“请求 - 响应”链中可能会有不同的效果。它用来向后兼容只支持 HTTP/1.0 协议的缓存服务器,那时候 HTTP/1.1 协议中的 Cache-Control 还没有出来。
备注: 由于 Pragma 在 HTTP 响应中的行为没有确切规范,所以不能可靠替代 HTTP/1.1 中通用首部 Cache-Control,尽管在请求中,假如 Cache-Control 不存在的话,它的行为与 Cache-Control: no-cache 一致。建议只在需要兼容 HTTP/1.0 客户端的场合下应用 Pragma 首部。
1. 分布式系统里last-modified
需要保持一致,以免负载到不同的机器导致比对失败,从而返回新资源。
2. 分布式系统尽量关闭掉Etag
,因为每一台服务器生成的Etag
是不同的
paragma -> Cache-control -> expires -> Etag -> last-modified
3种控制不走缓存的方法。
去除浏览器在请求头加上的If-Modified-Since或If-None-Match字段,并加上Pragma: no-cache和Cache-Control: no-cache字段。
Pragma: no-cache和Cache-Control: no-cache表示不走强制缓存,由于去掉了协商缓存的字段,导致也无法走协商缓存。
注意:ctrl+f5只不过能够管控、