博客首页前端开发分类

缓存那点事儿

发布时间:2019-10-14 10:55:16编辑:Mr.Co阅读(3300)

前端开发

大纲 

一、常见的几种浏览器缓存方式 
二、常见的几种服务端缓存方式 
三、浏览器缓存之Http缓存 
四、常见禁止缓存的几种方式 
五、前端缓存及代码打包部署的方式 
六、总结 

前言. 

缓存我们有的时候需要利用它来提升页面的响应速度,也有的时候不需要它的默认缓存行为,那我们如何在工作场景中合理的运用它呢?
首先我们需要先了解下它都有哪些缓存方式,然后才有对策让它不缓存。 我们可以看下浏览器通过代理服务器向源服务器发起请求的原理,如下图  
前端开发

浏览器先向代理服务器发起Web请求,再将请求转发到源服务器。它属于共享缓存,所以很多地方都可以使用其缓存资源,因此对于节省流量有很大作用。 浏览器缓存是将文件保存在客户端,在同一个会话过程中会检查缓存的副本是否足够新,在后退网页时,访问过的资源可以从浏览器缓存中拿出使用。通过减少服务器处理请求的数量,用户将获得更快的体验。 

一、常见的几种浏览器缓存方式 

1. 页面Meta缓存,此方式仅仅对页面缓存,不会对页面资源进行缓存,如<META HTTP-EQUIV="Pragma" CONTENT="no-store">
2.http缓存 
3.indexDB 
4.cookie 
5.localstorage 

二、常见的几种服务端缓存方式 

1.数据库缓存 
2.代理服务器缓存 
3.CDN 缓存 

三、浏览器缓存之Http缓存 

浏览器缓存分为强缓存协商缓存两种,
浏览器加载一个页面的简单流程如下 
 ①浏览器先根据这个资源的http头信息来判断是否命中强缓存。如果命中则直接加在缓存中的资源,并不会将请求发送到服务器。
 ②如果未命中强缓存,则浏览器会将资源加载请求发送到服务器。服务器来判断浏览器本地缓存是否失效。若可以使用,则服务器并不会返回资源信息,浏览器继续从缓存加载资源。
 ③如果未命中协商缓存,则服务器会将完整的资源返回给浏览器,浏览器加载新资源,并更新缓存。 

"页面的缓存状态是由header决定的,header的参数有四种" 

1.Cache-Control(强缓存
 ① max-age(单位为s)指定设置缓存最大的有效时间,定义的是时间长短。当浏览器向服务器发送请求后,在max-age这段时间里浏览器就不会再向服务器发送请求了。
 ② s-maxage(单位为s)同max-age,只用于共享缓存(比如CDN缓存)。 比如,当s-maxage=60时,在这60秒中,即使更新了CDN的内容,浏览器也不会进行请求。也就是说max-age用于普通缓存,而s-maxage用于代理缓存。如果存在s-maxage,则会覆盖掉max-age和Expires header。 
 ③ public 指定响应会被缓存,并且在多用户间共享。也就是下图的意思。如果没有指定public还是private,则默认为public。 
 ④ private 响应只作为私有的缓存(见下图),不能在用户间共享。如果要求HTTP认证,响应会自动设置为private。
 ⑤ no-cache 指定不缓存响应,表明资源不进行缓存,但是设置了no-cache之后并不代表浏览器不缓存,而是在缓存前要向服务器确认资源是否被更改。因此有的时候只设置no-cache防止缓存还是不够保险,还可以加上private指令,将过期时间设为过去的时间。
 ⑥ no-store 绝对禁止缓存,一看就知道如果用了这个命令当然就是不会进行缓存啦~每次请求资源都要从服务器重新获取。
 ⑦ must-revalidate指定如果页面是过期的,则去服务器进行获取。这个指令并不常用 

2.Expires(强缓存
 缓存过期时间,用来指定资源到期的时间,是服务器端的具体的时间点。也就是说,Expires=max-age + 请求时间,需要和Last-modified结合使用。但在上面我们提到过,cache-control的优先级更高。 Expires是Web服务器响应消息头字段,在响应http请求时告诉浏览器在过期时间前浏览器可以直接从浏览器缓存取数据,而无需再次请求。  

3.Last-modified(协商缓存
 服务器端文件的最后修改时间,需要和cache-control共同使用,是检查服务器端资源是否更新的一种方式。当浏览器再次进行请求时,会向服务器传送If-Modified-Since报头,询问Last-Modified时间点之后资源是否被修改过。如果没有修改,则返回码为304,使用缓存;如果修改过,则再次去服务器请求资源,返回码和首次请求相同为200,资源为服务器最新资源。 如下图,


最后修改时间为2014年12月19日星期五2点50分47秒 

4.ETag(协商缓存) 
根据实体内容生成一段hash字符串,标识资源的状态,由服务端产生。浏览器会将这串字符串传回服务器,验证资源是否已经修改,如果没有修改,过程如下:  


使用ETag可以解决Last-modified存在的一些问题:     
a、某些服务器不能精确得到资源的最后修改时间,这样就无法通过最后修改时间判断资源是否更新      
b、如果资源修改非常频繁,在秒以下的时间内进行修改,而Last-modified只能精确到秒      
c、一些资源的最后修改时间改变了,但是内容没改变,使用ETag就认为资源还是没有修改的。 

四、常见禁止缓存的几种方式 

1. <meta http-equiv='pragma' content='no-cache'> //HTTP-1.1 之前的历史遗留字段,仅作为与HTTP/1.0的向后兼容而定义

    <meta http-equiv='cache-control' content='no-cache,must-revalidate'>

    <meta http-equiv='expires' content='0'>

2. <body onLoad='javascript:document.formName.reset();'>

3. ajax请求设置xmlHttprequestHeader('If-Modified-Since','0')requestHeader('Cache-Control','no-cache')

4. 所有资源后面加时间戳或者随机码,比如http://mrco.cn/logo.jpg?r= Math.random();

5. 服务端responseheader头中加上Cache-Control:no-cache.


五、前端缓存后的代码打包部署方式 

问题一:有了缓存,如何进行前端代码更新呢? 
我们可以在资源文件或者图片后面添加版本号,如下图。 




问题二:但是所有文件都加了版本号之后,我们只更改了一个文件,其他文件的缓存不是浪费了吗?
解决这个问题,我们可以用 数据摘要要算法,对文件求摘要信息,摘要信息与文件内容一一对应。如下图:  


这样就解决了这个问题。 

问题三:新的问题又来了,文件发布怎么办? 
1、先部署页面,再部署资源:在二者部署的时间间隔内,如果有用户访问页面,就会在新的页面结构中加载旧的资源,并且把这个旧版本的资源当做新版本缓存起来,其结果就是:用户访问到了一个样式错乱的页面,除非手动刷新,否则在资源缓存过期之前,页面会一直执行错误。 
2、先部署资源,再部署页面:在部署时间间隔之内,有旧版本资源本地缓存的用户访问网站,由于请求的页面是旧版本的,资源引用没有改变,浏览器将直接使用本地缓存,这种情况下页面展现正常;但没有本地缓存或者缓存过期的用户访问网站,就会出现旧版本页面加载新版本资源的情况,导致页面执行错误,但当页面完成部署,这部分用户再次访问页面又会恢复正常了。 好的,上面一坨分析想说的就是:先部署谁都不成!都会导致部署过程中发生页面错乱的问题。所以,访问量不大的项目,可以让研发同学苦逼一把,等到半夜偷偷上线,先上静态资源,再部署页面,看起来问题少一些。 如何解决这些问题呢? 这个问题,起源于资源的 覆盖式发布,用 待发布资源 覆盖 已发布资源,就有这种问题。解决它也好办,就是实现 非覆盖式发布,如下图:  


看上图,用文件的摘要信息来对资源文件进行重命名,把摘要信息放到资源文件发布路径中,这样,内容有修改的资源就变成了一个新的文件发布到线上,不会覆盖已有的资源文件。上线过程中,先全量部署静态资源,再灰度部署页面,整个问题就比较完美的解决了。 

六、总结 

浏览器第一次请求:

  


浏览器再次请求时:  



延伸阅读:
https://www.cnblogs.com/futan/archive/2013/04/21/cachehuancun.html
https://www.keycdn.com/blog/http-cache-headers


转载请注明出自:http://www.mrco.cn/article/5da3e39450d36a3a09fc2547.html

最新评论(0)

    我要评论

    *
    *
    *
    *
    *
    *
    验证码