大前端百科全书浏览器专题之浏览器缓存

342 阅读10分钟

大前端百科全书,前端界的百科全书,记录前端各相关领域知识点,方便后续查阅及面试准备

关键词

关键词:强缓存、协商缓存、

  • 浏览器缓存机制(强缓存、协商缓存、缓存位置)
  • 301、302、304 的区别

一 浏览器缓存机制(强缓存、协商缓存、缓存位置)

浏览器缓存主要分为四个阶段

  • 强制缓存阶段:现在本地查找该资源,如果有发现该资源,而且该资源还没有过期,就使用这一个资源,完全不会发送 http 请求到服务器
  • 协商缓存阶段:如果在本地缓存找到对应的资源,但是不知道该资源是否过期或者已经过期,则发一个 http 请求到服务器,然后服务器判断这个请求,如果请求的资源在服务器上没有改动过,则返回 304,让浏览器使用本地找到的那个资源
  • 启发式缓存阶段:当缓存过期时间的字段一个都没有的时候,浏览器下次并不会直接进入协商阶段,而是先进入启发式缓存阶段,它根据响应头中 2 个时间字段 Date 和 Last-Modified 之间的时间差值,取其值的 10%作为缓存时间周期。也就是说:当存有 Last-Modified 字段的时候,即使是断网,且强缓存都失效后,也有一段时间是直接读取缓存文件的。etag 是没有这个阶段的。
  • 缓存失败阶段:当服务器发现请求的资源已经修改过,或者这是一个新的请求(在本来没有找到资源),服务器则返回该资源的数据,并且返回 200,当然这个是指找到资源的情况下,如果服务器上没有这个资源,则返回 404。

强缓存

浏览器中的缓存作用分为两个情况,一种是需要发送HTTP请求,一种是不需要发送

首先是检查强缓存,这个阶段不需要发送http请求

如何来检查呢?通过相应的字段来进行,但是说起这个字段就有意思啦

在http/1.0和http/1.1当中,这个字段是不一样的。

在早期,也就是http/1.0时期,使用的是Expires,而http/1.1使用的是Cache-Contronl

Expires

Expries即过期的时间,存在于服务端返回的响应头中,告诉浏览器在这个过期时间之前可以直接从缓存里面获取数据,无需再次请求

Expires: Wed, 22 Nov 2020 08:30:00 GMT

表示资源在2020年11月22号8点30分过期,过期了就得向服务端发送请求

这个方式看上去没什么问题,合情合理,但其实潜藏了一个坑,那就是服务器的时间和浏览器的时间可能并不一致,

那服务器返回的这个过期时间可能就是不准确的,因此这种方式很快在后来的http/1.1版本就抛弃了。

Cache-Control

在http1.1中,采用了一个非常关键的字段:Cache-Control。 它和Expires本质的不同在于它并没有采用具体的过期时间点这个方式,而是采用过期时长来控制缓存,对应的字段是max-age,比如这个例子:

Cache-Control: max-age=3600

代表这个响应返回后在3600秒,也就是一个小时之内可以直接使用缓存

如果你觉得它只有max-age一个属性的话,那就想错了

它其实可以组合非常多的指令,完成更多的场景的缓存判断,将一些关键的属性列举如下:

  • public:客户端和代理服务器都可以缓存。因为一个请求可能要经过不同的代理服务器最后才到达目标服务器,那么结果就是不仅仅浏览器可以缓存数据,中间的任何代理节点都可以进行缓存
  • private:只有浏览器能缓存,中间的代理服务器不能缓存
  • no-cache:跳过当前的强缓存,发送http请求,即直接进入协商缓存阶段
  • no-store:非常简单粗暴,不进行任何形式的缓存
  • s-maxage:这和max-age长得非常像,但是区别在于s-maxage是针对代理服务器的缓存时间。

值得注意的是:当Expires和Cache-Control同时存在的话,Cache-Control会优先考虑

还存在一种情况是:当资源缓存时间超时了,也就是强缓存失效了,接下就要进入第二部分协商缓存

协商缓存

强缓存失效之后,浏览器在请求头中携带相应的缓存tag来向服务器发请求,由服务器根据这个tag来决定是否使用缓存,这就是协商缓存 具体来说,这样的缓存tag分为两种:Last-Modified和ETag。这两者各有优劣之分,并不存在谁对谁有绝对的优势

Last-Modified

最后的修改时间。在浏览器第一次给服务器发送请求时,服务器会在响应头中加上这个字段 浏览器接收到后,如果再次请求,会在请求头中携带if-Modified-Since字段,这个字段的值也就是服务器传来的最后修改时间 服务器拿到请求头中的If-Modified-Since的字段后,其实会和这个服务器中该资源的最后修改时间对比: 如果请求头中的这个值小于最后修改时间,说明是时候更新了。返回新的资源,跟常规的http请求响应的流程一样 否则返回304,告诉浏览器直接用缓存

ETag

ETag是服务器根据当前文件的内容,给文件生成的唯一标识,只要里面的内容有改动,这个值就会变。服务器通过响应头把这个值给浏览器。浏览器接收到ETag的值,会在下次请求时,将这个值作为If-None-Match这个字段的内容,并放到请求头中,然后发送给服务器 服务器接接收到If-None-Match后,会跟服务器上该资源的ETag进行对比: 如果两者不一样,说明要更新了。返回新的资源,跟常规的http请求响应的流程一样 否则返回304,告诉浏览器直接用缓存

两者对比

  1. 在精准度上,ETag优于Last-Modified。优于ETag是按照内容给资源上标识,一次能准确感知资源的变化。而Last-Modified就不一样了,它在一些特殊的情况并不能准确感知资源变化,主要有两种情况
    • 编辑了资源文件,但是文件内容并没有更改,这样也会造成缓存失效
    • Last-Modified能够感知的单位时间是秒,如果文件在1秒内改变了多次,那么这时候的Last-Modified并没有体现出修改了
    • 如果文件是通过服务器动态生成的,那么该方法的更新时间永远是生成的时间,尽管文件可能没有变化,所以起不到缓存的作用
  2. 在性能上,Last-Modified由于ETag,也很简单理解,Last-Modified仅仅只是记录一个时间点,而ETag需要根据文件的具体内容生成哈希值
    • 计算 Etag 值需要性能损耗;
    • 分布式服务器存储的情况下,计算 Etag 的算法如果不一样,会导致浏览器从一台服务器上获得页面内容后到另外一台服务器上进行验证时现 Etag 不匹配的情况。

另外,如果两种方式都支持的话,服务器优先考虑ETag

缓存位置

当强缓存命中或者协商缓存中服务器返回304的时候,我们直接从缓存中获取资源。那么这些资源究竟缓存在什么位置呢?

浏览器中的缓存位置一共有四种:按优先级从高到低排列分别是:

  • Service Worker
  • Memory Cache
  • Disk Cache
  • Push Cache

Service Worker

Service Worker借鉴了Web Worker的思路,既让js运行在主线程之外,由于它脱离了浏览器的窗体,因此无法直接访问DOM。虽是如此,但它仍然能帮助我们完成很多有用的功能,比如离线缓存、消息推送和网络代理等功能。其中的离线缓存就是Service Worker Cache

Memory Cache、Disk Cache

Memory Cache指的是内存缓存,从效率上讲它是最快的。但是从存活时间来讲又是最短的,当渲染进程结束后,内存缓存也就不存在了。 Disk Cache就是存储在磁盘中的缓存,从存取效率上讲是比内存缓存慢的,但是它的优势在于存储容量和存储时长。

那浏览器如何决定将资源放进内存还是硬盘呢?

  • 比较大的js、css文件会直接被丢进磁盘,反之丢进内存
  • 内存使用率比较高的时候,文件优先进入磁盘

Push Cache

推送缓存,是一种低级的网络功能-使用网络堆栈的任何东西都可以使用它,有用的关键是一致性和可预测性,这是浏览器缓存的最后一道防线,它是http/2中的内容,虽然现在应用的并不广泛,但随着http/2的推广,它的应用越来越广泛。

对浏览器的缓存机制来做个总结

  • 首先强缓存可用,直接使用
  • 否则进入协商缓存,即发送HTTP请求,服务器通过请求头中的If-Modified-Since或者If-None-Match字段检查资源是否更新
  • 若资源更新,返回资源和200状态码
  • 否则返回304,告诉浏览器直接从缓存获取资源

二、301/302/304的区别

301

301 表示永久重定向(301 moved permanently),表示请求的资源分配了新 url,以后应使用新 url

302

302 表示临时性重定向(302 found),请求的资源临时分配了新 url,本次请求暂且使用新 url。302 和 301 的区别是:302 表示临时性重定向,重定向的 url 还有可能还会改变

304

304 虽然属于 3xx 类别中但是和重定向没有关系,304 是一个非常好玩的状态,当浏览器拿到状态码是 304 的时候,就会从本地资源中拿请求的资源或者代理服务器直接返回本地的资源,304 属于走缓存

访问服务器,发现数据没有更新,服务器返回奚状态码(不返回资源)。然后从缓存中读取数据。

协商缓存

  1. 将缓存信息中的 Etag 和 Last-Modified 通过请求发送给服务器
  2. 由服务器校验,返回 304 状态码时,浏览器直接使用缓存