什么是HTTP缓存?
涉及到Web缓存的范围很广,本文集中在浏览器缓存部分知识。
- ⼀个⽹络请求简单来讲三步:请求、处理、响应。
- 排除“处理”部分,前端的缓存可以在“请求”和“响应”中进⾏。
- 在“请求”部分,浏览器可以在存储结果中直接获得资源,省去了发送⽹络请求。
- 在“响应”部分,需要浏览器和服务器共同配合,通过减少响应内容来缩短传输时间。
使用缓存的作用:
- 减少⻚⾯加载时间
- 减少服务器压⼒
- 减少宽带消耗
存在哪儿?
- Service Worker
- Memory Cache
- Disk Cache
- ⽹络请求
memory cache
Memory Cache是内存中的缓存;- 先读内存,再读硬盘
- 只是“短期存储”,当浏览器tab关闭后失效。如果占据内存过⼤,会提前失效。
- memory cache 机制保证了⼀个⻚⾯中如果有两个相同的请求都实际只会被请求⼀次,以避免浪费。(是有类型区别的)
- 在从
Memory Cache是获得缓存内容时,浏览器会忽略如 maxage=0,no-cache 等头部配置。 memory cache是浏览器为了加快读取缓存速度⽽进⾏的⾃身优化⾏为,不受开发者控制,也不受HTTP协议头的约束,算是⼀个⿊盒。
disk cache
- 也叫
http cache,顾名思义是存储在硬盘上的缓存,因此它是持久存储的,实际存在于⽂件系统中的。disk cache会严格根据 HTTP 头信息同的各类字段来判定哪些资源可以被缓存,哪些不能;哪些资源是过时需要重新请求的。 - 浏览器是否使⽤缓存、缓存多久,都是由服务器决定的。
- 浏览器会⾃动清理缓存资源。
缓存(失效)策略
强制缓存
强制缓存:当客户端请求后,会先访问缓存数据库查看缓存是否存在。
- 存在 =》 直接返回
- 不存在 =》 请求服务器,响应后再写⼊缓存数据库中。
强制缓存直接减少请求数,是提升最⼤的缓存策略,应该最先被考虑。
Expires
Expires: Thu, 10 Nov 2020 08:45:11 GMT
HTTP 1.0 的字段,表示缓存到期时间,是⼀个绝对时间(当前时间 + 缓存时间),在响应消息头中,设置这个字段之后,就可以告诉浏览器,在未过期之前不需要再次请求。
缺点:
- ⽤户修改客户端本地时间,导致浏览器判断失效。
- 写法复杂,⼗分容易⾮法操作。
Cache-control
Cache-control: max-age=2592000
在 HTTP/1.1 中,增加了⼀个字段 Cache-control,该字段表示资源缓存的最⼤有效时间max-age,在该时间内,客户端不需要向服务器发送请求。
与 Expires 的区别就是 前者是绝对时间,后者是相对时间。从 HTTP 1.1 开始,Expires 逐渐被 Cache-control 取代。
Cache-control 的优先级⾼于 Expires,为了兼容 HTTP/1.0 和 HTTP/1.1,实际项⽬中两个字段都应该设置。
Cache-control常⽤字段:
- max-age: 最⼤有效时间;
- must-revalidate:如果超过了 max-age 的时间,浏览器必须向服务器发送请求,验证资源是否还有效;
- no-cache:是否使⽤这个内容由后续的对⽐来决定;
- no-store:真正意义上的“不要缓存”;
- public:所有的内容都可以被缓存;
- private:所有的内容只有客户端可以缓存,代理服务器不能缓存;
- 这些值可以混⽤的: Cache-control:public, max-age=2592000
协商(对比)缓存
当强制缓存失效时,就需要使⽤对⽐缓存,由服务器决定缓存内容是否失效。、
流程:
- 请求缓存数据库,返回⼀个缓存标识;
- 拿到这个标识跟服务器通讯;
- 返回状态码 304 表示继续使⽤;
- 否则返回新的数据和缓存规则,浏览器响应数据后,将规则写⼊缓存数据库。
Last-Modified & If-Modified-Since
服务器通过 Last-Modified 字段告知客户端,资源最后 ⼀次被修改的时间,例如:
Last-Modified: Mon, 10 Nov 2020 09:10:11 GMT
浏览器将这个值和内容⼀起记录在缓存数据库中;下⼀次请求相同资源时,浏览器从⾃⼰的缓存中找出 “不确定是否过期” 的缓存。
在请求头中将上次的 Last-Modified 的值写⼊到请求头的If-Modified-Since 字段中。
服务器将 If-Modified-Since 的值与 Last-Modified 字段进⾏对⽐:
- 相等,表示未修改,响应304;
- 反之,表示修改了,响应200,并返回数据。
Last-Modified & If-Modified-Since 缺陷
- 如果资源更新的速度是秒以下单位,那么该缓存是不能被使⽤的,因为它的时间单位最低是秒。
- 如果⽂件是通过服务器动态⽣成的,那更新时间永远都是⽣成的时间,尽管⽂件可能没有变化,但起不到缓存的作⽤。
Etag & If-None-Match
Etag 存储的是⽂件的特殊标识(⼀般都是hash⽣产的),服务器存储着⽂件的 Etag 字段。
流程跟 Last-Modified 是⼀致的。
优先级⾼于 Last-Modified。
浏览器的⾏为
指的是⽤户在浏览器如何操作时,会触发缓存策略。
-
开发⽹⻚,地址栏输⼊地址:浏览器会查看 disk cache中,有则⽤,⽆则发送请求。
-
普通刷新:因为TAB并没有关闭,因此 memory cache 是可⽤的,会被优先使⽤,其次是disk cache。
-
强制刷新(ctrl + F5):由于是不适⽤缓存,状态码200并返回请求内容。
⼀些最佳实践
不常变的资源:
如引入lodash.js、Jquery.js等等,短期内不考虑更换的资源
- 设置 Cache-Control: max-age= 31536000
- ⽂件名(或者路径)中添加hash,版本号等动态字符;
- 或者在URL后⾯添加参数(例如?v=XXX 或者 _=XXX);
经常变的资源:
- 设置 Cache-Control: no-cache
- 静态资源服务器或者类库会解决