先说一个前端开发中会遇到的问题,我们更新已上线的项目,用户的浏览器显示的却是旧版的页面,没有及时获取到我们更新的资源,这是什么原因造成的?此时,如果用户刷新一下页面,就得到更新后的资源,又是为什么?

答案是 浏览器缓存

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

(1)减少冗余的数据传输,节省带宽;

(2)减轻服务器的请求负担,有缓存就可以少向服务器发送请求,尤其是对于一些访问量大的网站这点还是很重要的;

(3)资源从缓存中读取,无需向服务器发送请求再等待返回,加快了客户端的访问速度。

但是缓存同样给前端带来了一个很严重的问题,就是上面所说的项目更新的问题。如果项目更新了,但是用户访问时浏览器读取的是缓存资源,那么用户就获取不到最新的页面,影响用户使用。

接下来就从浏览器缓存开始分析出现项目更新问题的原因,并给出相应的解决方法。

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

一、HTTP状态码

在讨论浏览器缓存之前,我们先看看网页相关的http状态码,打开控制台,在Network下捕捉请求,注意Status和Size栏,会看到200 from disk cache,200数值大小。

刷新页面,会看到,304 数值大小,200 from memory cache。

    这几个有什么不同呢?200和304是常见的两个http状态码,200表示文件发生改动,304表示文件未改动,都是服务器返回告知的。在上面两张图中,我们注意到,有些200是灰色的,灰色的200表示没有向服务器发送请求,而是直接从缓存中读取。从缓存中读取又分为从内存(from memory cache)中读取还是从磁盘中读取(from disk cache)。

总结一张表:

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

浏览器有三级缓存原理:

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

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

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

结合我们的问题,假设某个用户打开过我们的页面,然后我们更新了文件,用户再去访问,资源加载情况是200 from disk cache,浏览器根本没有请求服务器,所以拿不到新的资源文件。那么,有没有办法解决这种情况?浏览器缓存机制是什么样的?

二、浏览器缓存

浏览器缓存分两种:强制缓存 和 协商缓存(对比缓存)

1、强制缓存

强制缓存就是,用户第一次访问页面之后,浏览器将数据存在缓存中,在过期时间之内,都不会再请求服务器。是否使用强制缓存在于资源是否过期,该过期时间从第一次请求的服务器响应头中获取。如果在过期时间内,从缓存中读取,如果超出过期时间,则使用协商缓存(下面会讲)。

控制强制缓存的字段分别是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]. 浏览器的协商缓存与强缓存

[2]. 10分钟彻底搞懂Http的强制缓存和协商缓存

再回到我们的问题,用户打开浏览器发现是旧的资源,于是手动刷新了一下页面,得到了新的资源,这是为什么呢?

3、用户行为会对缓存产生影响


结合上面的内容,我们可以分析情况了:

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

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

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

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

我们再看几张图应该就很好理解了






三、解决方法

明白了问题所在,我们接下来就可以提出对应的解决方法了。

  • 方法一:

以vue为例,vue在打包的时候,css和js名字都加了哈希值,所以改动后打包生成的js和css是唯一的,页面请求的是新资源,不会有缓存问题。但是入口文件index.html会因为缓存造成更新问题,如果我们更新了,但是浏览器使用的是缓存,就会出现问题。所以需要对入口文件设置不使用强制缓存,需要每次去服务器验证文件是否修改,即使用协商缓存。

使用nginx反向代理,在nginx.conf文件的对应server中设置,目前我自己实践出的可行的一种写法是:

server {listen       80;server_name  域名;root   文件目录;index  index.html;location / {  // 不加这一句,会出现nginx欢迎页面,无法正确加载资源try_files $uri /index.html;}location ~ .*\.(html)$ {  // 对html文件限制缓存add_header Cache-Control no-store;  // 不缓存// 或者用add_header Cache-Control no-cache;替代上面那一句,协商缓存add_header Pragma no-cache;}}
  • 方法二(摘自其他博文,未经过验证)
  1. 最直接的办法
    Internet选项-》Internet临时文件“设置”-》“每次访问此页时检查”,缺点是要设置每台客户端,客户端较多时不可取

  2. 设置网页头(header)

HTML页面:

<META HTTP-EQUIV="pragma" CONTENT="no-cache">
<META HTTP-EQUIV="Cache-Control" CONTENT="no-cache, must-revalidate">
<META HTTP-EQUIV="expires" CONTENT="Mon, 23 Jan 1978 20:52:30 GMT">

ASP页面:

<%
Response.Expires = -1
Response.ExpiresAbsolute = Now() - 1
Response.cachecontrol = "no-cache"
%>

PHP页面:

header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
header("Cache-Control: no-cache, must-revalidate");
header("Pragma: no-cache");

JSP页面:

<%
response.setHeader("Pragma","No-Cache");
response.setHeader("Cache-Control","No-Cache");
response.setDateHeader("Expires", 0);
%>
  1. 简单有效的办法
    在访问的URL后面拼接随机数作为参数:
var randomNum = Math.random();
url += "&randomNum="+randomNum;


说明:

(1)Cache-Control: no-cache和Cache-Control: no-store区别

看字面意思容易误解,no-cache就是不缓存,但是no-cache并不是不缓存,而是使用协商缓存,所以并不能禁止缓存,no-store才是真正的禁止缓存。从节省带宽角度讲,使用no-cache更优一点,文件未发生改变时只传输很小的报文大小,只有在文件改变时才会传输整个文件大小。而不是no-store不管什么情况都传输整个文件大小。

(2)Pragma: no-cache:和Cache-Control: no-cache区别

Pragma: no-cache跟Cache-Control: no-cache相同,Pragma: no-cache兼容http 1.0 ,Cache-Control: no-cache是http 1.1提供的。因此,Pragma: no-cache可以应用到http 1.0 和http 1.1,而Cache-Control: no-cache只能应用于http 1.1.

参考文章:

彻底理解浏览器的缓存机制

浏览器缓存带来的前端项目更新问题及解决方法相关推荐

  1. java工程编辑器中文乱码_Java Web开发项目中中文乱码解决方法汇总

    Java Web项目中,解决中文乱码方法总结如下 第一种情况:调用jsp页面中文显示乱码问题描述:通过浏览器调用jsp页面,在浏览器中显示的中文内容出现乱码. 解决方法:首先确认本jsp在编辑器中保存 ...

  2. win10更新后应用无法连接服务器,win10更新无法连接到更新服务怎么办_win10无法连接到更新服务的解决方法...

    最近有朋友问小编win10更新无法连接到更新服务怎么办,对于这个问题,相信很多朋友都遇到过,有时候我们想更新自己的win10版本,却发现win10更新无法连接到更新服务,这是怎么回事呢?遇到windo ...

  3. ios和平精英更新显示无法连接服务器,和平精英ios更新不了怎么办 ios更新不了解决方法...

    和平精英ios更新不了怎么办?很多IOS玩家在更新时遇到更新不了或者更新慢的情况,那么这样怎么解决呢?以下是小编为大家整理的解决方法,来了解一下吧. 网络问题 建议切换成无线网络,然后退出游戏后重新进 ...

  4. 此服务器不支持该安装程序,macOS 提示“不能安装该软件,因为当前无法从软件更新服务器获得” 解决方法...

    原标题:macOS 提示"不能安装该软件,因为当前无法从软件更新服务器获得" 解决方法 有些小伙伴安装苹果开发者工具command line tools时,会提示"不能安 ...

  5. pubg国服服务器维修怎么解决 ios,刺激战场ios更新不了解决方法_绝地求生刺激战场ios更新不了怎么办_4月25日刺激战场ios更新后进不去_9号资讯...

    第 2 页 刺激战场ios更新不了解决方法 解决方法一 点击苹果商店右下角的[更新],在[待更新项目]中直接点击更新,玩家不必进入游戏,直接到苹果商店里面进行更新即可.若依然无法更新,可尝试解决方法二 ...

  6. 辐射76服务器无响应 控制台暂停使用,辐射76更新后卡死解决方法介绍 中途卡死退出处理方法...

    原标题:辐射76更新后卡死解决方法介绍 中途卡死退出处理方法 <辐射76>在近期进行了一波游戏性的更新修复了不少的BUG和问题,不过不少玩家在更新后遇到了卡死的问题,下面就为大家带来具体的 ...

  7. eclipse下tomcat添加部署Module,Web名称与项目名称不一致的解决方法

    eclipse下tomcat添加部署Module,Web名称与项目名称不一致的解决方法 参考文章: (1)eclipse下tomcat添加部署Module,Web名称与项目名称不一致的解决方法 (2) ...

  8. chrome浏览器模拟手机端:jquery click()点击无效解决方法

    chrome浏览器模拟手机端:jquery click()点击无效解决方法 参考文章: (1)chrome浏览器模拟手机端:jquery click()点击无效解决方法 (2)https://www. ...

  9. CSS学习笔记--浮动元素由于浏览器页面缩小而被挤到下面的解决方法

    CSS学习笔记--浮动元素由于浏览器页面缩小而被挤到下面的解决方法 参考文章: (1)CSS学习笔记--浮动元素由于浏览器页面缩小而被挤到下面的解决方法 (2)https://www.cnblogs. ...

最新文章

  1. 实现费用管理 mysql_电信资费管理系统的设计与实现(NetBeans,MySQL)
  2. 应用按home键无最近应用
  3. 智能巡检云监控指标的实践
  4. hibernate简单应用
  5. 每日小记 2017.6.29
  6. 乐凯PMP2106项目管理考试资料大全,包含四套模拟试卷
  7. 微信小程序云开发教程-手把手:小程序数据库设计
  8. 使用 Apache FOP 2.3 + docbook-xsl-ns-1.79.1 转换 Docbook 5.1 格式的 XML 文档成 PDF/RTF 文件
  9. mysql 分区 线性hash_MySQL表分区(3)哈希分区-hash
  10. 前端字体图标的使用总结
  11. word文档中文字字符长度不一,如何快速调整使上下行左右对齐
  12. Spark的坑--Spark新手必看--Python Spark必读,耗费了我近三周的时间
  13. 面试专题:QTrade(苹果树)面试复盘
  14. [分享]深思--求索人的心智 就是求索长青基业
  15. 主流搜索引擎蜘蛛的IP地址网段整理
  16. 如何写一份优秀的商业计划书
  17. app2sd 与 A2SD+
  18. Python学习笔记之Python之禅
  19. HFSS学习笔记 21 扫频分析
  20. ssm基于Java和MySql的产业信息管理系统的设计与实现毕业设计源码260839

热门文章

  1. 肖特基二极管型号大全之ASEMI肖特基常见型号
  2. ORA-27101异常处理
  3. 登录psn 服务器无响应,PSN港服账号无法登陆,账户与此主机的出厂设定不相容的解决方法...
  4. linux软件包管理(RPM)简单介绍
  5. 思科路由器的时间配置
  6. 微信小程序红包开发注意事项
  7. 雷达系统 学习笔记(七)——相控阵雷达2
  8. 计算机考研和leetcode难度,2021计算机考研真题难度解析
  9. 蓝桥杯刷题冲刺 | 倒计时7天
  10. 六十五、完成Vue项目去哪儿网App首页开发(来源:慕课网)