📜 cache的作用:
- 缓存发现请求的资源已经被存储,它会拦截请求,返回该资源的拷贝,而不会去源服务器重新下载。缓解了服务器端压力。
- 减少了等待时间和网络流量,因此减少了显示资源表示形式所需的时间。显著提高网站和应用程序的性能。
*怎么样工作? *当客户端请求后,会先访问缓存数据库看缓存是否存在。如果存在则直接返回;不存在则请求真的服务器,响应后再写入缓存数据库。
三级缓存原理:
- 先去内存查找,如果有,直接加载
- 如果内存没有,择取硬盘获取,如果有直接加载
- 如果硬盘也没有,那么就进行网络请求,加载到的资源缓存到硬盘和内存
📜 cache的类型:
-
强制缓存:相比于协商缓存客户端请求会先读取强缓存。
Cache-control 的优先级高于 Expires,为了兼容 HTTP/1.0 和 HTTP/1.1,实际项目中两个字段我们都会设置。-
http/1.0版本,
Expires表示缓存到期时间,是一个绝对的时间戳 (当前时间+缓存时间)。缺陷:由于是绝对时间,用户可能会将客户端本地的时间进行修改,而导致浏览器判断缓存失效,重新请求该资源。此外,即使不考虑修改,时差或者误差等因素也可能造成客户端与服务端的时间不一致,致使缓存失效。
-
http/1.1版本,
Cache-control该字段表示资源缓存的最大有效时间,在该时间内,客户端不需要向服务器发送请求Cache-control 字段常用的值: s-maxage: 设置代理服务器缓存的最大的有效时间,单位为秒(s)。s-maxage会覆盖掉max-age。 max-age:即最大有效时间,在上面的例子中我们可以看到。max-age会覆盖掉expires。 must-revalidate:如果超过了 max-age 的时间,浏览器必须向服务器发送请求,验证资源是否还有效。 no-cache:虽然字面意思是“不要缓存”,但实际上还是要求客户端缓存内容的,只是是否使用这个内容由后续的对比来决定。 no-store: 真正意义上的“不要缓存”。所有内容都不走缓存,包括强制和对比。 public:所有的内容都可以被缓存 (包括客户端和代理服务器, 如 CDN) private:所有的内容只有客户端才可以缓存,代理服务器不能缓存。默认值。
-
-
协商缓存:当没有使用强制缓存或强缓存失效(超过规定时间)时,就需要使用协商缓存,由服务器决定缓存内容是否失效。浏览器先请求缓存数据库,返回一个缓存标识。之后浏览器拿这个标识和服务器通讯。如果缓存未失效,则返回 HTTP 状态码 304 表示继续使用,于是客户端继续使用缓存;如果失效,则返回新的数据和缓存规则,浏览器响应数据后,再把规则写入到缓存数据库。
Etag 的优先级高于 Last-Modified。 在协商缓存没有失效时,服务端只会返回响应头,并不会返回实体。-
http/1.0版本,
Last-Modified&If-Modified-SinceLast-Modified&If-Modified-Since,服务器通过Last-Modified字段告知客户端,资源最后一次被修改的时间。
- 下一次请求相同资源时时,浏览器从自己的缓存中找出“不确定是否过期的”缓存。因此在请求头中将上次的
Last-Modified的值写入到请求头的If-Modified-Since字段。
-
服务器会将
If-Modified-Since的值与Last-Modified字段进行对比。如果相等,则表示未修改,响应 304;反之,则表示修改了,响应 200 状态码,并返回数据。
-
缺陷:
- 如果资源更新的速度是秒以下单位,那么该缓存是不能被使用的,因为它的时间单位最低是秒;
- 如果文件是通过服务器动态生成的,那么该方法的更新时间永远是生成的时间,尽管文件可能没有变化,所以起不到缓存的作用;
- 编辑了文件,但文件的内容没有改变。服务端并不清楚我们是否真正改变了文件,它仍然通过最后编辑时间进行判断。因此这个资源在再次被请求时,会被当做新资源,进而引发一次完整的响应——不该重新请求的时候,也会重新请求。
-
http/1.1版本,
Etag&If-None-MatchEtag存储的是文件的特殊标识(一般都是 hash 生成的),服务器存储着文件的Etag字段。之后的流程和Last-Modified一致,只是Last-Modified字段和它所表示的更新时间改变成了Etag字段和它所表示的文件 hash,把If-Modified-Since变成了If-None-Match。服务器同样进行比较,命中返回 304, 不命中返回新资源和 200。
-
📜 cache的位置:
关于缓存存放位置的划分规则,纠结了很久。查了很多文章,内存是有限的,很多时候需要先考虑即时呈现的内存余量,再根据具体的情况决定分配给内存和磁盘的资源量的比重——资源存放的位置具有一定的随机性。
虽然不知道划分规则,但根据日常开发中观察的结果,我们至少可以总结出这样的规律:Base64 格式的图片,几乎永远可以被塞进 memory cache;此外,体积不大的 JS、CSS 文件,也有较大地被写入内存的几率——相比之下,较大的 JS、CSS 文件就没有这个待遇了,内存资源是有限的,它们往往被直接甩进磁盘。
根据浏览器内存空闲情况,如果内存使用率很低就优先放入内存,反之则放入磁盘。对于一些大的文件,浏览器还是放在了磁盘内存里,因为大文件太占内存空间。
graph TD;
ServiceWorker-->MemoryCache-->DiskCache-->网络请求;
webkit的资源分类主要分为两大类:主资源和派生资源。
-
WebKit派生资源包含的类型主要如下:
Javascript脚本(CachedScript);
CSS样式文本(CachedCSSStyleSheet);
图片(CachedImage);
字体(CachedFont);
XSL样式表(CachedXSLStyleSheet);
200 from memory cache
不访问服务器,直接读缓存,从内存中读取缓存。此时的数据时缓存到内存中的,当kill进程后,也就是浏览器关闭以后,数据将不存在。但是这种方式只能缓存派生资源。
200 from disk cache
不访问服务器,直接读缓存,从磁盘中读取缓存,当kill进程时,数据还是存在。这种方式也只能缓存派生资源
304 Not Modified
访问服务器,发现数据没有更新,服务器返回此状态码。然后从缓存中读取数据。(协商缓存每次都会发起 HTTP 请求,但当缓存内容仍有效时可以跳过 HTTP 响应体的下载)
memory cache和disk cache的特性
-
内存缓存(from memory cache):内存缓存具有两个特点,分别是快速读取和时效性:
- 时效性:一旦该进程关闭,则该进程的内存则会清空。
- 快速读取:内存缓存会将编译解析后的文件,直接存入该进程的内存中,占据该进程一定的内存资源,以方便下次运行使用时的快速读取。
- 硬盘缓存(from disk cache):硬盘缓存则是直接将缓存写入硬盘文件中,读取缓存需要对该缓存存放的硬盘文件进行I/O操作,然后重新解析该缓存内容,读取复杂,速度比内存缓存慢。
-
[*push cache** ] *:是指 HTTP2 在 server push 阶段存在的缓存。这块的知识比较新:
- Push Cache 是缓存的最后一道防线。浏览器只有在 Memory Cache、HTTP Cache 和 Service Worker Cache 均未命中的情况下才会去询问 Push Cache。
- Push Cache 是一种存在于会话阶段的缓存,当 session 终止时,缓存也随之释放。
- 不同的页面只要共享了同一个 HTTP2 连接,那么它们就可以共享同一个 Push Cache。
📜 列举cache的几种应用模式:
缓存静态资源,不常变化的资源
Cache-Control: public, max-age=31536000 //public表示那么它既可以被浏览器缓存,也可以被代理服务器缓存
//private则表示该资源只能被浏览器缓存。private 为默认值。
Cache-Control: max-age=36000, s-maxage=31536000//如果设置了 s-maxage,但没设置 public,那么 CDN 还是可以缓存这个资源的。
经常变化的资源
no-cache 绕开了浏览器:我们为资源设置了 no-cache 后,每一次发起请求都不会再去询问浏览器的缓存情况,而是直接向服务端去确认该资源是否过期(协商缓存)。
no-store 顾名思义就是不使用任何缓存策略。在 no-cache 的基础上,它连服务端的缓存确认也绕开了,只允许你直接向服务端发送请求、并下载完整的响应。
Cache-Control: no-cache //指定 no-cache 或 max-age=0, must-revalidate 表示客户端可以缓存资源,
//每次使用缓存资源前都必须重新验证其有效性。
Cache-control: no-store
💡客户端缓存导致用户无法及时更新到新版本?
location ~ /xxxx {
...other config
if ($request_filename ~* .*.(htm|html)$) {
add_header Pragma no-cache; //Pragma: no-cache可以兼容http 1.0和http 1.1,
// add_header Cache-Control "private, no-store, no-cache, must-revalidate, proxy-revalidate";
}
if ($request_filename ~* .*.(js|css|svg|eot|woff|ttf|gif|jpe?g|png|bmp|webp|swf|mp3|ico)$) {
add_header expires 60d;
add_header Cache-Control max-age=5184000;
}
}