为什么会有浏览器缓存策略
- 减少重复数据请求,避免通过网络再次加载资源,节省流量。
- 降低服务器的压力,提升网站性能。
- 加快客户端加载网页的速度, 提升用户体验。
何谓 【强缓存 vs 协商缓存】
强缓存:
若浏览器有缓存副本且未过期,则直接使用强缓存版本 cache-control: max-age
协商缓存:
即使本地有副本,也会携带缓存标识 If-modified-since/If-none-match
到服务器验证副本有效性,
如果生效返回304
,负责直接返回200
页面如何命中 强缓存和协商缓存?
首先我们引用上面这幅经典的流程图进行说明:
- 浏览器在访问页面的时候,判断页面是否有被缓存过,如果有缓存,直接从缓存中读取数据进行访问即可。
- 如果没有缓存或缓存已过期,访问页面后,服务器会在
Response Headers
(在 Header 内的字段用于控制缓存机制)中返回一个Etag
的标识符,第二次访问此页面时,会在Request Headers
(在 Header 内的字段用于控制缓存机制)中携带对应的If-none-match
,这个If-none-match
和上面后端返回的Etag
是一致的,因为值是Etag
的值,这时候服务器会进行决策,如果返回200
则请求响应,进行缓存协商。如果返回304
,则从缓存读取。 - 步骤同2,如果
Etag
没有,则对应的查看是否有last-modified
….. - 如果
Etag
和last-modified
都不存在,此时就只能服务器请求新的资源了…
网址链接实例讲解
我们以 juejin.cn 为例进行讲解
首次访问新链接后,页面会走协商缓存,服务端会在Response Headers
中返回一个Etag
的标识符。
再次(第二次)访问此链接后,Request Headers
中携带对应的If-none-match
,这个If-none-match
和上面后端返回的Etag
是一致的。此时携带此标识(If-none-match)到服务器端验证副本有效性,如果生效返回304
,否则直接返回结果200
间隔一段时间后,缓存失效后,再次访问juejin.cn链接后, If-none-match和Etag不一致
,此时缓存时效,此时会重新请求服务器获取新的资源
画个图 总结一下(这里以Etag和If-none-match为例):
Last-Modified和If-modified-since流程同Etag和If-none-match一致
Etag是服务器响应请求时,返回当前资源文件的一个唯一标识(由服务器生成),If-none-match是客户端再次发起该请求时,携带上次请求返回的唯一标识Etag值,通过此字段值告诉服务器该资源上次请求返回的唯一标识值。服务器收到该请求后,发现该请求头中含有If-none-match,则会根据If-none-match的字段值与该资源在服务器的Etag值做对比,一致则返回304,代表资源无更新,继续使用缓存文件;不一致则重新返回资源文件,状态码为200。
If-modified-since则是客户端再次发起该请求时,携带上次请求返回的Last-Modified值,通过此字段值告诉服务器该资源上次请求返回的最后被修改时间。服务器收到该请求,发现请求头含有If-modified-since字段,则会根据If-modified-since的字段值与该资源在服务器的最后被修改时间做对比,若服务器的资源最后被修改时间大于If-modified-since的字段值,则重新返回资源,状态码为200;否则则返回304,代表资源无更新,可继续使用缓存文件
Etag/If-none-match
优先级高于 Last-Modified/If-modified-since
Last-Modified/Etag
区别
相同点:
- 两者都是用来处理协商缓存的
不同点:
- last-modified 是根据文件修改时间,它的优点是计算量会更小,它就是根据文件的存储时间判断;但缺点就是非内容块改变(比如:只是meta标签发生了变化,但文件内容没有变化的情况下)系统也会判断这是一个新修改过的文件,这个时候就可能会造成缓存失效,还有就是last-modified单位是秒,如果一秒内修改了文件,last-modified是检测不到的。基于上面几种情况,所以选用了 Etag
- Etag 是根据文件内容算出摘要,只有内容变化,Etag才会发生变化,那这样就可以保证,一定是文件内容发生了变化,缓存才会失效。缺点就是有一个摘要的计算(现在是依托在服务器的
nginx
中做摘要计算),可能会比较耗时
所以现在我们常用的比较好的缓存实践就是:
- 文件名使用
hash
做路径标识 + 配合强缓存 - 应用缓存 —
App Cache and Manifest
文件 - 用
localstorage
— 做缓存 Service Worker
— 实现自定义的网络请求逻辑
在HTTP/1.1中,Cache-Control是最重要的规则,主要用于控制网页缓存
Cache-Control:
- public:所有内容都将被缓存(客户端和代理服务器都可缓存)
- private:所有内容只有客户端可以缓存,Cache-Control的默认取值
- no-cache【
重点
】:告诉浏览器、缓存服务器,不管本地副本是否过期(last-modified)适应资源副本前一定要到原服务器进行副本有效性校验. 简单理解就是:指示浏览器每次使用url的缓存版本之前都必须与服务器重新验证
- no-store:所有内容都不会被缓存,即不使用强制缓存,也不使用协商缓存
- max-age=xxx (xxx is numeric):缓存内容将在xxx秒后失效
- must-revalidate:告诉浏览器、缓存服务器,本地副本过期前,可以使用本地副本;本地副本一旦过期,必须去源服务器进行有效性校验
注意:cache-control: max-age=0
暗示内容立即被认为是陈旧的(并且必须重新获取),这实际上与cache-control: no-cache
相同
注意点:
- 获取缓存检测缓存是否过期,如果没过期取缓存
- 优先从内存,其次硬盘,如果过期,则与服务器协商缓存是否仍然可用,如果不可用则获取,可用取缓存
- cache会在页面关闭时写入磁盘,下次打开同一站点时检测到未过期则会使用disk
如果文章有错误或者不严谨的地方,请务必给予指正,十分感谢 ~