浏览器缓存造成的获取不到最新页面资源问题

lxf2023-03-15 07:55:01

本篇文章是个人的查漏补缺的学习记录,有不足和错误欢迎指正~

工作中遇到的问题

实际工作中有时候会发现前端更新线上的项目后,用户浏览器显示的还是旧版的页面,需要刷新浏览器才能获取最新的页面内容。或者前端有个下载静态资源的链接,文件改变而链接不变的情况下我们总是下载到老版本的文件,而不是重新从静态资源服务器去请求。

浏览器缓存是前端优化的一个重要问题,缓存可以带来很多好处:

  • 减少冗余的数据传输,节省带宽;
  • 减轻服务器的请求负担,有缓存就可以少向服务器发送请求,尤其是对于一些访问量大的网站这点还是很重要的;
  • 资源从缓存中读取,无需向服务器发送请求再等待返回,加快了客户端的访问速度。

但是当用户访问时浏览器读取的是缓存资源,那么用户就获取不到最新的页面,影响用户使用。就会造成上述的问题出现。缓存是把双刃剑,在享受它带来的好处和便利时我们也要接受和搞明白它可能造成的问题。

浏览器缓存

浏览器缓存主要指http缓存,其机制是根据http报文的缓存标识进行相应操作。

http状态码

打开控制台的Network栏,注意Status和Size栏,会看到200状态 disk cache和内存缓存。

浏览器缓存造成的获取不到最新页面资源问题 刷新页面,会看到304、200  内存缓存

浏览器缓存造成的获取不到最新页面资源问题 200和304是常见的两个http状态码,200表示文件发生改动,304表示文件未改动,都是服务器返回告知的。在上面两张图中,我们注意到,有些200是灰色的,灰色的200表示没有向服务器发送请求,而是直接从缓存中读取。从缓存中读取又分为从内存(from memory cache)中读取还是从磁盘中读取( disk cache)

状态描述
200 from memory cache状态码是灰色的,从内存中读取之前已经加载过的资源,不请求服务器,页面关闭时,资源就会被内存释放,再次打开相同页面不会出现此类情况,在同一页面刷新才会出现。一般脚本、字体、图片会存在内存当中
200 from disk cache状态码是灰色的,从磁盘中读取之前已经加载过的资源,不请求服务器,页面关闭不会被释放,这部分资源存在电脑磁盘里,只有用户手动清除浏览器缓存的时候才会释放。一般非脚本会存在内存当中,如css等
200 数值大小从服务器下载最新资源,数值是从服务器获取的全部资源大小
304 数值大小访问服务器,发现资源没有更新,使用本地资源。数值是与服务器通信报文的大小,并不是资源本身的大小。

还有size栏的值是“prefetch cache(预提取缓存)”,则是浏览器的prefetch机制。

浏览器有三级缓存原理

    1、先查找内存,如果内存中存在,从内存中加载;

    2、如果内存中未查找到,选择硬盘获取,如果硬盘中有,从硬盘中加载;

    3、如果硬盘中未查找到,那就进行网络请求,加载到的资源缓存到硬盘和内存;

参考一张简单过程图: 浏览器缓存造成的获取不到最新页面资源问题 结合上面工作中遇到的问题,假设某个用户打开过我们的页面,然后我们更新了文件,用户再去访问,资源加载情况是200 from disk cache,浏览器根本没有请求服务器,所以拿不到新的资源文件。

缓存过程分析

想要解决之前提到的问题,就需要对浏览器的缓存机制有了解。 浏览器缓存分两种:强制缓存和协商缓存(对比缓存)

   1、强制缓存

当浏览器向服务器发起请求时,服务器会将缓存规则放入HTTP响应报文的HTTP头中和请求结果一起返回给浏览器,控制强制缓存的字段分别是Expires和Cache-Control,其中Cache-Control优先级比Expires高。 用户第一次访问页面之后,浏览器将数据存在缓存中,在过期时间之内,都不会再请求服务器。是否使用强制缓存在于资源是否过期,该过期时间从第一次请求的服务器响应头中获取。如果在过期时间内,从缓存中读取,如果超出过期时间,则使用协商缓存(下面会讲)。上面的200 from memory cache和200 from disk cache属于强制缓存。

2、协商缓存

协商缓存,是浏览器和服务器之间协商,那么浏览器每次都要和服务器通信。 在第一次请求服务器时,服务器会返回资源,并且返回一个资源的缓存标识,一起存到浏览器的缓存数据库。当第二次请求资源时,浏览器会首先将缓存标识发送给服务器,服务器拿到标识后判断标识是否匹配,如果不匹配,表示资源有更新,服务器会将新数据和新的缓存标识一起返回到浏览器;如果缓存标识匹配,表示资源没有更新,并且返回 304 状态码,浏览器就读取本地缓存服务器中的数据。

    与协商缓存有关的字段是Last-Modified/IF-Modified-Since、Etag/IF-None-Match。

    Last-Modified与ETag是可以一起使用的,服务器会优先验证ETag,一致的情况下,才会继续比对Last-Modified,最后才决定是否返回304。

用户打开浏览器发现是旧的资源,于是手动刷新了一下页面,得到了新的资源,这是为什么呢? 用户的不同行为会对缓存产生影响:

浏览器缓存造成的获取不到最新页面资源问题 1、用户第一次访问页面——200 数值大小,与服务器通信,服务器返回全部资源大小,浏览器把获取到的数据根据缓存规则进行缓存。

    2、更新项目,用户打开页面是旧的资源——200 from disk cache,命中强缓存,使用了本地缓存,没有请求服务器

    3、用户手动刷新页面,得到新资源——200 数值大小,用户刷新,强缓存失效,使用协商缓存,根据缓存标识发现资源修改了,服务器返回全部新资源和缓存标识

    4、用户再刷新页面——304 数值大小,协商缓存,资源没有修改,数值不是全部资源大小,是报文信息大小。同时,这里会出现一些资源200 from memory的情况,它们存在内存中。

不同情况下的过程可以参考下面几张图:

浏览器缓存造成的获取不到最新页面资源问题 浏览器缓存造成的获取不到最新页面资源问题 浏览器缓存造成的获取不到最新页面资源问题 浏览器缓存造成的获取不到最新页面资源问题 浏览器缓存造成的获取不到最新页面资源问题 浏览器缓存造成的获取不到最新页面资源问题

解决方法

如果是一些静态资源链接,比如一个文档,我们希望在用户每次点击下载时获取到的都是最新的文档,可以在链接后加上一个随机参数,比如static.xxxx.com/xxx/xxx.zip => static.xxxx.com/xxx/xxx.zip…; 对于js和css文件来说,一般我们在使用打包工具打包时都会在css和js名字前加上哈希值,所以每次打包生成的js和css是唯一的,不会有缓存问题。但是对于像index.html,就需要使用协商缓存而不是强缓存,将html文件的Cache-Control设置为no-store。

参考文章: www.cnblogs.com/SallyShan/p…