今天看啥  ›  专栏  ›  miao8862

浏览器缓存

miao8862  · 简书  ·  · 2021-04-20 23:44

浏览器加载网络资源的速度,其中一个重要手段是 利用缓存

Web 缓存按存储位置来区分,包括 数据库缓存、服务端缓存、CDN 缓存和浏览器缓存 。下面主要介绍浏览器缓存。

浏览器缓存的 核心问题 是: 如何保证缓存与实际资源一致的同时,提高缓存的命中率 (尽可能地让浏览器从缓存中获取资源,但同时又要保证被使用的缓存与服务端最新的资源保持一致)。

http缓存的分类及原理

http缓存有两种缓存过期策略,即强缓存和协商缓存。

强缓存

在设定的过期时间之前,浏览器都不会再向服务器请求资源,而是直接使用浏览器缓存 。

expires
http 1.0时使用响应头 expires 来实现:浏览器第一次向服务器请求资源时,服务器响应时,会在响应头expires设置一个过期时间,在这个过期时间前,浏览器如果再次请求,会直接从浏览器缓存中查找,如果找不到,才会向服务器请求。
Expires: Thu,21 Jan 2017 23:39:02 GMT
Expires表示的是绝对时间,是服务器的绝对时间,可能和客户端时间不一致,也就是 客户端可以通过手动修改系统时间,从而导致缓存延长使用或提前过期的问题

Cache-Control
http 1.1增加Cache-Control响应头来改善这个问题,它可以有以下几个值:

  • no-cache:表示使用协商缓存,即每次使用缓存前必须向服务端确认缓存资源是否更新;
  • no-store:禁止浏览器以及所有中间缓存存储响应内容;
  • public:公有缓存,表示可以被代理服务器缓存,可以被多个用户共享;
  • private:私有缓存,不能被代理服务器缓存,不可以被多个用户共享;
  • max-age:以秒为单位的数值,表示缓存的有效时间;
  • must-revalidate:当缓存过期时,需要去服务端校验缓存的有效性。

Cache-Control:max-age=3600 (这个是相对时间,是相对于客户端时间的3600s)

如果 expires 和 Cache-Control 两者同时存在,则以cache-control为准 ,强缓存是由服务器设置的,但是是由浏览器来判断缓存是否还有效

协商缓存

不再设置缓存时间,而是直接由浏览器向服务器发送请求进行缓存确认,如果服务器返回304状态码,则表示缓存仍然有效。

Last-Modified和If-Modified-Since
利用服务器和客户的修改时间比对来判断:

  1. 客户端第一次向服务器请求资源
  2. 服务器返回资源,并在响应头设置 Last-Modified告知上次修改时间
  3. 客户端再次请求资源时,会将服务器上次返回的Last-Modified修改时间,作为这次请求头If-Modified-Since的时间,用于询问服务器自这个时间起,这个资源是否修改了
  4. 服务器收到请求后,比对双方资源修改时间来判断缓存是否过期,如果没过期,返回304;如果过期了,重新返回资源和更新时间
  • 响应头: Last-Modified Last-Modified: Wed, 26 Jan 2017 00:35:11 GMT
  • 请求头: If-Modified-Since:Wed, 26 Jan 2017 00:35:11 GMT

但这种做法仍存在问题:

  1. 时间精度问题 :如果修改文件是在1s以内,内容修改了,但时间没变,误判使用缓存
  2. 内容准度问题 :我打开了文件,没修改任何内容(或者修改后又改回去了),重新保存,内容没变,但时间变了,会误判不使用缓存

ETag 和 If-None-Match
为了解决以上两个问题,http提供一种基于文件哈希值来判断缓存的方式:

  1. 客户端第一次请求资源
  2. 服务端返回资源,响应头添加 ETag,为资源文件的哈希值
  3. 客户端再次请求时,以上次服务器的ETag值作为自己这次请求头If-None-Match的值,用于询问服务器文件是否修改过
  4. 服务器比对If-None-Match的值和现在资源的哈希值,如果没变,返回304,使用缓存;否则返回新资源和对应的ETag值
  • 响应头: Etag
  • 请求头: If-None-Match

存在的问题:

  1. 计算成本高,当文件大时,计算它的哈希值开销比较大
  2. 当资源放置在不同服务器时,不同服务器计算哈希值方式不一样时,返回的ETag值不一样,导致相同的资源却没命中缓存。即 使用服务器集群时,可能会降低缓存命中率

协商缓存是由客户端和服务端共同设置的,由服务端判断是否命中缓存。

优先级:

  1. 强缓存高于协商缓存
  2. 强缓存中:cache-control高于expires
  3. 协商缓存中:Etag高于last-modified

Service Worker

ServiceWorker 是浏览器在后台独立于网页运行的脚本,也可以这样理解,它是浏览器和服务端之间的代理服务器。ServiceWorker 非常强大,可以实现包括推送通知和后台同步等功能,更多功能还在进一步扩展,但其最主要的功能是实现 离线缓存

主要 实现原理 :拦截浏览器请求并返回缓存的资源文件。

大概实现流程是这样的:

  1. 先使用register注册serviceWorker脚本,浏览器获取到脚本后会解析然后进行安装
  2. 通过监听install事件来监听安装,当安装完成后激活脚本
  3. 激活脚本后,可以监听fetch事件来拦截请求并加载缓存的资源

因为它的功能很强大,所以浏览器对其做了很多限制:

  1. 在 ServiceWorker 中无法直接访问 DOM,但可以通过 postMessage 接口发送的消息来与其控制的页面进行通信;
  2. ServiceWorker 只能在本地环境下或 HTTPS 网站中使用;
  3. ServiceWorker 有作用域的限制,一个 ServiceWorker 脚本只能作用于当前路径及其子路径;
  4. 兼容性不太好(IE不支持),具体可以到caniuse网站查询



原文地址:访问原文地址
快照地址: 访问文章快照