vlambda博客
学习文章列表

面试题锦(3) | 说说浏览器的缓存策略

前言

「面试题锦」的初衷是为了记录我的前端学习轨迹,在整理记录的过程中对我而言也是一种,欢迎你跟着我每周重点攻克一个前端面试重难点。在进阶的路上,共勉!

1. 说说浏览器的缓存策略

浏览器缓存位置和优先级

  1. Service Worker
  2. Memory Cache(内存缓存)
  3. Disk Cache(硬盘缓存)
  4. Push Cache(推送缓存)
  5. 以上缓存都没命中就会进行网络请求

不同缓存位置的差别

「Service Worker」:和Web Worker类似,是独立的线程,我们可以在这个线程中缓存文件,在主线程需要的时候读取这里的文件,Service Worker使我们可以自由选择缓存哪些文件以及文件的匹配、读取规则,并且缓存是持续性的。

「Memory Cache」:即内存缓存,内存缓存不是持续性的,缓存会随着进程释放而释放。

「Disk Cache」:即硬盘缓存,相较于内存缓存,硬盘缓存的持续性和容量更优,它会根据HTTP header的字段判断哪些资源需要缓存。

「Push Cache」:即推送缓存,是HTTP/2的内容,目前应用较少。

浏览器缓存策略

缓存分为「强缓存」和「协商缓存」。设置为强缓存,之后的请求都不访问服务器,直接从缓存中找,默认返回状态码是200,且默认强制缓存不缓存首页资源;设置为协商缓存后,每次请求仍然要向服务器询问缓存是否过期,返回状态码是304。「两种缓存机制同时存在时,强缓存高于协商缓存。」

强缓存(不要向服务器询问的缓存)

  • 「设置Expires(HTTP1.0)」:即过期时间,表示缓存会在这个时间后失效,这个过期日期是绝对日期,如果修改了本地日期,或者本地日期与服务器日期不一致,那么将导致缓存过期时间错误。
res.setHeader('Expires'new Date(Date.now()+3600*1000).toGMTString());
  • 「设置Cache-Control(HTTP/1.1)」:HTTP/1.1新增字段,Cache-Control可以通过max-age字段来设置过期时间,除此之外Cache-Control还有很多属性,不同的属性代表不同的含义:

    • private:客户端可以缓存
    • public:客户端和代理服务器都可以缓存
    • max-age=t:缓存内容将在t秒后失效
    • 「no-cache」: 「默认值」,需要使用协商缓存来验证缓存数据,意思不是不缓存,而是 「请求且缓存」。
    • 「no-store」:真正不缓存,意思是 「请求但不缓存」。
res.setHeader('Cache-Control''max-age=3600');
res.setHeader('Cache-Control''no-cache');

请注意no-cache指令很多人误以为是不缓存,这是不准确的,no-cache的意思是可以缓存,但每次都会向服务器验证缓存是否可用。no-store才是不缓存。当在首部字段 Cache-Control 有指定 max-age 指令时,**Cache-Control的 max-age 优先级高于 Expires。**命中强缓存的表现形式:Firefox浏览器表现为一个灰色的200状态码。Chrome浏览器状态码表现为200 (from disk cache)或是200 OK (from memory cache)。

协商缓存(当缓存已经过期时,使用协商缓存)

  • 「Last-Modified & if-Modified-Since(HTTP/1.0)」:对比修改时间

    「缺点」:内容没变时间变化了,也会重新读取内容;时间不精准,时间的最小粒度只到ss以内的改动无法检测到。

    • 「Last-Modified」:即最后修改时间,浏览器第一次请求资源时,服务器会在响应头上加上Last-Modified,告诉浏览器资源的最后修改时间。

    • 「if-Modified-Since」:当浏览器再次请求该资源时,浏览器会在请求头中带上If-Modified-Since字段,字段的值就是之前服务器返回的最后修改时间,服务器对比这两个时间,若相同,浏览器直接从缓存中获取数据信息。返回状态码304;若不同则返回新资源,返回状态码200,并更新Last-Modified

  • 「Etag & If-None-Match」:对比唯一标识,这种比较方式比较精准,但是默认不会根据完整内容生成唯一标识;为了保证精确度,我们一般会用内容的一部分+文件的总大小来生成唯一标识。「Etag 的优先级高于 Last-Modified」。

    「缺点」:文件内容越大,越耗性能

    • 「Etag(HTTP/1.1)」:服务器响应请求时,通过此字段告诉浏览器当前资源在服务器生成的唯一标识(生成规则由服务器决定)。

    • 「If-None-Match」:当浏览器再次请求该资源时,浏览器会在请求头中带上If-None-Match字段,字段的值就是在缓存中获取的唯一标识。服务器对比两次请求的标识,若相同说明资源没有被修改,浏览器直接从缓存中获取数据信息。返回状态码304;若不同则说明资源被改动过,响应整个资源内容,返回状态码200。

缓存场景

对于大部分的场景都可以使用强缓存配合协商缓存解决,但是在一些特殊的地方可能需要选择特殊的缓存策略

  • 对于某些不需要缓存的资源,可以使用 Cache-control: no-store ,表示该资源不需要缓存
  • 对于频繁变动的资源,可以使用 Cache-Control: no-cache 并配合 ETag 使用,表示该资源已被缓存,但是每次都会发送请求询问资源是否更新
  • 对于代码文件来说,通常使用 Cache-Control: max-age=31536000 并配合策略缓存使用,然后对文件进行指纹处理,一旦文件名变动就会立刻下载新的文件

2.  HTTP/1.0和HTTP/1.1有什么区别

  • 「持久连接」:HTTP/1.1 支持持久连接和请求的流水线,在一个TCP连接上可以传送多个HTTP请求,只要浏览器或者服务器没有明确断开连接,那么该 TCP 连接会一直保持,这样的好处是避免了因为多次建立TCP连接的时间消耗,减少了服务器额外的负担,并提升整体 HTTP 的请求时长。目前浏览器中对于同一个域名,「默认允许同时建立 6 个 TCP 持久连接。」

  • 「缓存处理」:HTTP/1.1 引入Entity tag,If-Unmodified-Since, If-Match, If-None-Match等新的请求头来控制缓存。

  • 「对动态生成的内容提供了完美支持」:随着服务器端的技术发展,很多页面的内容都是动态生成的,因此在传输数据之前并不知道最终的数据大小,这就导致了浏览器不知道何时会接收完所有的文件数据。HTTP/1.1 通过引入 Chunk transfer 机制来解决这个问题,服务器会将数据分割成若干个任意大小的数据块,每个数据块发送时会附上上个数据块的长度,最后使用一个零长度的块作为发送数据完成的标志。这样就提供了对动态内容的支持。

  • 「客户端 Cookie、安全机制」:HTTP1.1 引入了 cookie 安全机制。

  • 「带宽优化及网络连接的使用」:HTTP1.1 则在请求头引入了 range 头域,支持断点续传功能。

3. 介绍一下HTTP/2.0新特性

  • 「多路复用」:一个域名都通过一个 TCP 连接并发地完成。主要是为了规避 TCP 的慢启动,TCP 连接之间的竞争问题和队头阻塞问题。

  • 「服务端推送」:服务端能够主动把资源推送给客户端。

  • 「可以设置请求的优先级」:在发送请求时,标上该请求的优先级,这样服务器接收到请求之后,会优先处理优先级高的请求。

  • 「新的二进制格式」:HTTP/2采用二进制格式传输数据,相比于HTTP/1.1的文本格式,二进制格式具有更好的解析性和拓展性。

  • 「头部压缩」:HTTP/2压缩消息头,减少了传输数据的大小。

4. 说说HTTP/3.0

尽管HTTP/2解决了很多1.1的问题,但HTTP/2仍然存在一些缺陷,这些缺陷并不是来自于HTTP/2协议本身,而是来源于底层的TCP协议,我们知道TCP链接是可靠的连接,如果出现了丢包,那么整个连接都要等待重传,HTTP/1.1可以同时使用6个TCP连接,一个阻塞另外五个还能工作,但HTTP/2只有一个TCP连接,阻塞的问题便被放大了。

由于TCP协议已经被广泛使用,我们很难直接修改TCP协议,基于此,HTTP/3选择了一个折衷的方法——UDP协议,HTTP/2在UDP的基础上实现多路复用、0-RTT、TLS加密、流量控制、丢包重传等功能。

非常感谢您看完了这篇文章,如果您觉得这篇内容对您有些许作用,那就请长按二维码关注我吧!

喜欢就关注我吧!