Vue项目部署上线清理浏览器缓存(一)

1,544 阅读8分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第25天,点击查看活动详情

前言

当前项目组使用的前端技术栈是vue+docker+nginx。项目一直正常运转,但是有一个特让人头疼的问题。那就是每次部署上线后就会有各种小问题,这个时候我一般会说:要不你清一下缓存?清缓存100%能解决问题。一直因为忙,没时间去处理,这段时间抽了点空,把问题解决了,顺道记录下。

缓存

缓存,是一种本地保存远端资源的一种机制。当使用相同的URL进行数据请求的时候,可以直接从缓存中取资源而不再访问服务器。从这个角度来看缓存是一种能改善性能以及用户体验的一种手段。他可以减少对网络贷款的消耗,减少网络延迟,从而加快网页打开机制。但是凡事都事两面的。缓存也不例外。他也同时具备一些让用户头疼的问题,那就是在某种情况下,依旧从缓存中取资源,但是实际服务器上资源已更新。 web缓存一般是按照其缓存数据存储的位置来区分。总共分为4类缓存。分别是:

  1. 数据库缓存
  2. 服务器缓存
  3. CDN缓存
  4. 浏览器缓存 由于本章主要解决部署上线浏览器缓存问题,所以本章主要讲浏览器缓存,后续会单独说明其他3个缓存

浏览器缓存

当前浏览器是通过http或者https请求来获取数据的,跟缓存命名一样,其也根据存储的位置来分为4大类。分别是:

  1. Service Worker 缓存
  2. 内存缓存
  3. 硬盘缓存
  4. 推送缓存 当我们通过URL请求数据的时候会从这4类缓存中取数据,当数据没有取到会通过请求从服务器请求。
Service Worker缓存

Service Worker是一个单独的线程,其与浏览器主线程是相互独立的。其消耗的内存不会堵塞主线程,因此一般处理需要消耗大量资源或者需要离线缓存的场景。如果需要使用Service Worker必须通过HTTPS请求,因为Service Worker可以劫持数据,如果通过HTTP请求会导致安全性的问题。下面就是一个最常见的Service Worker的示例:

window.addEventListener('load', function() {
    navigator.serviceWorker.register('/test.js').then(function(registration) {
      // Registration was successful
      console.log('ServiceWorker registration successful with scope: ', registration.scope);
    }, function(err) {
      // registration failed :(
      console.log('ServiceWorker registration failed: ', err);
    });
});

上面的代码说明,当页面加载完成后,注册/test.js.这个test.js文件按照这个配置是放服务器根目录下。当加载完成后,在Chrome浏览器中输入chrome://inspect/#service-workers查看你注册的缓存

内存缓存

也叫Memory Cache。是不是很熟悉。是的,当我们打开Chrome浏览器的控制台。其中的Memory就是显示的这个。其主要包含当前页面中已经被"抓取"的资源(CSS,JS,Image等)。当我们关闭了浏览器的tab页的时候,其缓存会被释放掉。一般会将小文件缓存在内存中,原因也很简单:因为不管是计算机还是移动设备,其内存一般都是比较小的。

硬盘缓存

也叫Disk Cache。是存储在硬盘中的缓存。由于读取其缓存的数据需要从硬盘中读取,因此他比内存缓存的读取速度要满。但是同样的因为其存储在硬盘中,所以他可以存储体积更大的数据。我们常见的硬盘缓存,可以通过Chrome浏览器中的Source页来看出,其中有一项Size中表明了是否是硬盘缓存数据。如图:

1650974819(1).jpg 硬盘缓存的原理是通过HTTP请求头中的字段去判断如何取数据:是直接缓存,还是取缓存中数据。还是过期了需要重新请求

推送缓存

也叫Push Cache,一般是当以上三种缓存没有找到数据,就会从推送缓存中取数据。他存在一个Session中。当会话结束后就消除。因此其缓存时间比较短暂。

缓存类型

当前根据缓存的过程,我们可以将向服务器发送请求的缓存,分为两类:

  1. 强制缓存
  2. 协商缓存
强制缓存

浏览器在加载资源的时候,会检查缓存是否存在,当不存在的情况下会直接向服务器请求,当缓存存在的时候会判断是否过期,如果过期,同样向服务器发送请求,反之直接存缓存中取数据。其过程如下图:

1650975612(1).jpg 那么浏览器如何判断缓存是否过期呢,这个时候就需要两个响应头了,那就是ExpiresCache-Control.

Expires

设置缓存过期时间。在第一次请求的时候,后端会在响应头增加此字段。当再次请求同样请求的时候,会对比当前时间与Expires设置的过期时间,来判断是否过期。但是单纯的通过Expires来判断是有问题的,原因有以下两点:

  1. 服务器和浏览器的时间可能会不同,这在我们日常开发中经常会遇到,这样就会导致过期时间不准确
  2. 我们可以修改电脑的系统时间,这样就会导致缓存失效,或者继续使用本身应该失效的缓存。 因此就有了另一个字段Cache-Control.
Cache-Control

Cache-Control是设置浏览器相对过期时间。以毫秒为单位。其可设置的值见下表:

名称描述
no-cache走协商缓存,每次从缓存中取数据前都会向服务端确认缓存资源是否更新
no-store禁止缓存任何数据
public表示缓存为共有缓存,可被代理服务器缓存,也可被多个用户共享
private表示私有缓存,与public对立,不能被代理服务器缓存,也不能被多个用户共享
max-age表示最大的缓存时间,以秒为单位,当过去后需要重新从服务器获取
must-revalidate当缓存过期时,需要去服务端校验缓存的有效性
max-stale请求方header中,机试缓存过期,在max-stale时间内还可以使用缓存(代理服务器中)

以上配置都可以重复设置,但是no-store优先级最高。例如:

cache-control:max-age = 2048000
cache-control:public

此配置说明该缓存的有效期为2048000秒,且是共有的缓存,可以被代理服务器缓存,也可以被多个用户共享。

协商缓存

协商缓存,顾名思义,他会跟去商量下是否缓存以及是否更新缓存。其不指定缓存的有效时间。并且在请求的时候会将表示传给服务器,来确认是否更新缓存。如果返回状态码为304.则表明缓存有效,从缓存中取数据,如果返回的状态码是200。则直接返回最新的数据。以及表示。其过程如下:

image.png 那么资源标识是啥呢?当前机制中资源标识有两种:

  1. Last-Modified
  2. Etag
Last-Modified

资源最后修改的时间,通过响应头来返回此数据,标识资源最后修改的时间,如果带有Last-Modified。再一次请求的时候,会将请求头带上if-Modified-Since,交给服务器,由服务器根据if-Modified-Since,判断资源是否变化,如果变化返回200以及新的资源标识,反之,返回304 Not Modified。其过程如下图:

image.png 但是单纯的通过Last-Modified依旧会存在判断不准确的情况。那就是:

  1. 由于有些服务器不能精准的得到文件的最后修改时间,会导致判断不准备
  2. 当一个文件删除再还原,其内容其实没有边,但是实际上服务器会认为改变了。会导致重新请求
  3. Last-Modified采用的是毫秒精度,因此在短时间内发生的变化,会导致重新请求。 基于以上三个问题,我们就需要另一个资源标识ETag
ETag

被请求变量的实体值。其值是服务器端针对文件所产生的一种文件哈希值。服务器根据此文件哈希值来精准判断缓存。当第一次请求的时候,服务器会在响应头中返回ETag数据。其值为资源文件的Hash值。当再次请求的时候,会在请求头上增加If-None-Match,值为上一次返回的ETag值。服务器根据请求头中的If-None-Match值跟服务器资源文件的Hash值对比。如果相同,返回304 Not Modified。反之返回资源,同时重新返回文件的Hash值放入响应头的ETag中.其过程如下:

image.png

优先级问题

在强制缓存中:cache-controlmax-age优先级高于Expires 在协商缓存中:ETag的优先级要高于Last-Modified. 因此我们可以得知整个浏览器缓存的过程如下图: (下次补充) 本章我们介绍了缓存,下一章我们将进入主题,那就是在Vue项目中如何自动的清除浏览器的缓存呢?敬请期待。