http协商缓存VS强缓存

正文开始

<p>https://www.cnblogs.com/wonyun/p/5524617.html</p><p><a id="cb_post_title_url" href="http://www.cnblogs.com/wonyun/p/5524617.html">http协商缓存VS强缓存</a></p><p>之前一直对浏览器缓存只能描述一个大概,深层次的原理不能描述上来;终于在前端的两次面试过程中被问倒下,为了泄恨,查阅一些资料最终对其有了一个更深入的理解,废话不多说,赶紧来看看浏览器缓存的那些事吧,有不对的地方,请各位不吝赐教啊。</p><p> 本文主要讲解浏览器端的缓存,缓存的作用是不言而喻的,能够极大的改善网页性能,提高用户体验。</p>1、浏览器缓存<p>缓存这东西,第一次必须获取到资源后,然后根据返回的信息来告诉如何缓存资源,可能采用的是强缓存,也可能告诉客户端浏览器是协商缓存,这都需要根据响应的header内容来决定的。下面用两幅图来描述浏览器的缓存是怎么玩的,让大家有个大概的认知。</p><p>浏览器第一次请求时:</p><p><img style="display: block; margin-left: auto; margin-right: auto;" src="http://img.li6.cc/content_img/1/article/140/408483-20160525182843100-1556227104.png" alt="" /></p><p>浏览器后续在进行请求时:</p><p><img style="display: block; margin-left: auto; margin-right: auto;" src="http://img.li6.cc/content_img/1/article/140/408483-20160525182943272-204994049.png" alt="" /></p><p> </p><p> 从上图可以知道,浏览器缓存包含两种类型,即强缓存(也叫本地缓存)和协商缓存,浏览器在第一次请求发生后,再次请求时:</p>浏览器在请求某一资源时,会先获取该资源缓存的header信息,判断是否命中强缓存(cache-control和expires信息),若命中直接从缓存中获取资源信息,包括缓存header信息;本次请求根本就不会与服务器进行通信;在firebug下可以查看某个具有强缓存资源返回的信息,例如本地firebug查看的一个强缓存js文件<br /><br /><img src="http://img.li6.cc/content_img/1/article/140/408483-20160525185916397-1208157783.png" alt="" height="297" width="517" /><br /><br />如果没有命中强缓存,浏览器会发送请求到服务器,请求会携带第一次请求返回的有关缓存的header字段信息(Last-Modified/If-Modified-Since和Etag/If-None-Match),由服务器根据请求中的相关header信息来比对结果是否协商缓存命中;若命中,则服务器返回新的响应header信息更新缓存中的对应header信息,但是并不返回资源内容,它会告知浏览器可以直接从缓存获取;否则返回最新的资源内容<p>强缓存与协商缓存的区别,可以用下表来进行描述:</p> 获取资源形式状态码发送请求到服务器强缓存 从缓存取 200(from cache)否,直接从缓存取协商缓存 从缓存取 304(not modified)是,正如其名,通过服务器来告知缓存是否可用<p style="text-align: left;"> </p>2、强缓存相关的header字段<p style="text-align: left;">强缓存上面已经介绍了,直接从缓存中获取资源而不经过服务器;与强缓存相关的header字段有两个:</p>expires,这是http1.0时的规范;它的值为一个绝对时间的GMT格式的时间字符串,如Mon, 10 Jun 2015 21:31:12 GMT,如果发送请求的时间在expires之前,那么本地缓存始终有效,否则就会发送请求到服务器来获取资源<br /><br />cache-control:max-age=number,这是http1.1时出现的header信息,主要是利用该字段的max-age值来进行判断,它是一个相对值;资源第一次的请求时间和Cache-Control设定的有效期,计算出一个资源过期时间,再拿这个过期时间跟当前的请求时间比较,如果请求时间在过期时间之前,就能命中缓存,否则就不行;cache-control除了该字段外,还有下面几个比较常用的设置值:<br /><br />no-cache:不使用本地缓存。需要使用缓存协商,先与服务器确认返回的响应是否被更改,如果之前的响应中存在ETag,那么请求的时候会与服务端验证,如果资源未被更改,则可以避免重新下载。<br /><br />no-store:直接禁止游览器缓存数据,每次用户请求该资源,都会向服务器发送一个请求,每次都会下载完整的资源。<br /><br />public:可以被所有的用户缓存,包括终端用户和CDN等中间代理服务器。<br /><br />private:只能被终端用户的浏览器缓存,不允许CDN等中继缓存服务器对其缓存。<p>  注意:如果cache-control与expires同时存在的话,cache-control的优先级高于expires</p>3、协商缓存相关的header字段<p style="text-align: left;">协商缓存都是由服务器来确定缓存资源是否可用的,所以客户端与服务器端要通过某种标识来进行通信,从而让服务器判断请求资源是否可以缓存访问,这主要涉及到下面两组header字段,这两组搭档都是成对出现的,即第一次请求的响应头带上某个字段(Last-Modified或者Etag),则后续请求则会带上对应的请求字段(If-Modified-Since或者If-None-Match),若响应头没有Last-Modified或者Etag字段,则请求头也不会有对应的字段。</p>Last-Modified/If-Modified-Since<br />二者的值都是GMT格式的时间字符串,具体过程:<br />浏览器第一次跟服务器请求一个资源,服务器在返回这个资源的同时,在respone的header加上Last-Modified的header,这个header表示这个资源在服务器上的最后修改时间<br /><br />浏览器再次跟服务器请求这个资源时,在request的header上加上If-Modified-Since的header,这个header的值就是上一次请求时返回的Last-Modified的值<br /><br />服务器再次收到资源请求时,根据浏览器传过来If-Modified-Since和资源在服务器上的最后修改时间判断资源是否有变化,如果没有变化则返回304 Not Modified,但是不会返回资源内容;如果有变化,就正常返回资源内容。当服务器返回304 Not Modified的响应时,response header中不会再添加Last-Modified的header,因为既然资源没有变化,那么Last-Modified也就不会改变,这是服务器返回304时的response header<br /><br />浏览器收到304的响应后,就会从缓存中加载资源<br /><br />如果协商缓存没有命中,浏览器直接从服务器加载资源时,Last-Modified的Header在重新加载的时候会被更新,下次请求时,If-Modified-Since会启用上次返回的Last-Modified值<br /><br />Etag/If-None-Match<br />这两个值是由服务器生成的每个资源的唯一标识字符串,只要资源有变化就这个值就会改变;其判断过程与Last-Modified/If-Modified-Since类似,与Last-Modified不一样的是,当服务器返回304 Not Modified的响应时,由于ETag重新生成过,response header中还会把这个ETag返回,即使这个ETag跟之前的没有变化。<br /><br /> 4、既生Last-Modified何生Etag<br />  你可能会觉得使用Last-Modified已经足以让浏览器知道本地的缓存副本是否足够新,为什么还需要Etag呢?HTTP1.1中Etag的出现主要是为了解决几个Last-Modified比较难解决的问题:<p>一些文件也许会周期性的更改,但是他的内容并不改变(仅仅改变的修改时间),这个时候我们并不希望客户端认为这个文件被修改了,而重新GET;</p><p>某些文件修改非常频繁,比如在秒以下的时间内进行修改,(比方说1s内修改了N次),If-Modified-Since能检查到的粒度是s级的,这种修改无法判断(或者说UNIX记录MTIME只能精确到秒);</p><p>某些服务器不能精确的得到文件的最后修改时间。</p><p>这时,利用Etag能够更加准确的控制缓存,因为Etag是服务器自动生成或者由开发者生成的对应资源在服务器端的唯一标识符。</p><p>Last-Modified与ETag是可以一起使用的,服务器会优先验证ETag,一致的情况下,才会继续比对Last-Modified,最后才决定是否返回304。</p>5、用户的行为对缓存的影响<p>盗用网上的一张图,基本能描述用户行为对缓存的影响</p><p><img style="" src="http://img.li6.cc/content_img/1/article/140/408483-20160525182843100-1556227104.png" alt="" /></p>6、强缓存如何重新加载缓存缓存过的资源<p>上面说到,使用强缓存时,浏览器不会发送请求到服务端,根据设置的缓存时间浏览器一直从缓存中获取资源,在这期间若资源产生了变化,浏览器就在缓存期内就一直得不到最新的资源,那么如何防止这种事情发生呢?</p><p>通过更新页面中引用的资源路径,让浏览器主动放弃缓存,加载新资源。</p><p>类似下图所示:</p><p><img src="http://img.li6.cc/content_img/1/article/140/8a8676e933478d1a73777d84a5de55f5_b.jpg" alt="" height="110" width="304" /></p><p>这样每次文件改变后就会生成新的query值,这样query值不同,也就是页面引用的资源路径不同了,之前缓存过的资源就被浏览器忽略了,因为资源请求的路径变了。</p><p> </p><p>具体的强烈推荐看知乎的这篇问答中张云龙的回答 <a href="https://www.zhihu.com/question/20790576" target="_blank">https://www.zhihu.com/question/20790576</a></p><p><br /></p><p><br /></p><p><a href="http://caibaojian.com/browser-cache.html" style="color:#666">浏览器的协商缓存与强缓存</a></p><p>http://caibaojian.com/browser-cache.html</p><p><br /></p><p>原文链接:<a href="http://caibaojian.com/browser-cache.html">http://caibaojian.com/browser-cache.html</a><br /></p><p>做前端有两个比较令人头痛的事,一个是命名,另一个就是缓存了。缓存的问题在移动端上尤其严重,因为手机随时随地会缓存你的资源,要想清缓存,不像PC使用强制刷新,还要手动找到<a href="http://caibaojian.com/t/%e6%b5%8f%e8%a7%88%e5%99%a8" title="View all posts in 浏览器" target="_blank">浏览器</a>的缓存,有时候还要重启等。下面这篇文章清晰的讲解关注浏览器的缓存,值得看看。<a href="http://caibaojian.com/browser-cache.html">·</a></p><a name="t1"></a>什么是浏览器缓存<p>浏览器缓存(Brower Caching)是浏览器在本地磁盘对用户最近请求过的文档进行存储,当访问者再次访问同一页面时,浏览器就可以直接从本地磁盘加载文档。</p><p>浏览器缓存的优点有:</p>减少了冗余的数据传输,节省了网费减少了服务器的负担,大大提升了网站的性能加快了客户端加载网页的速度<p>在<a href="http://caibaojian.com/" title="前端开发">前端开发</a>面试中,浏览器缓存是<a href="http://caibaojian.com/c/web" title="网站建设">web</a>性能优化面试题中很重要的一个知识点,从而说明浏览器缓存是提升web性能的一大利器,但是浏览器缓存如果使用不当,也会产生很多问题,正所谓是,想说爱你,并不是很容易的事。所以,结合最近遇到的案例,本文对浏览器缓存相关的知识进行总结归纳,希望对读者有所帮助。</p><a name="t2"></a>浏览器缓存的分类<p>浏览器缓存主要有两类:缓存协商和彻底缓存,也有称之为协商缓存和强缓存。</p><p>浏览器在第一次请求发生后,再次请求时:</p>浏览器会先获取该资源缓存的header信息,根据其中的expires和cahe-control判断是否命中强缓存,若命中则直接从缓存中获取资源,包括缓存的header信息,本次请求不会与服务器进行通信;如果没有命中强缓存,浏览器会发送请求到服务器,该请求会携带第一次请求返回的有关缓存的header字段信息(Last-Modified/IF-Modified-Since、Etag/IF-None-Match),由服务器根据请求中的相关header信息来对比结果是否命中协商缓存,若命中,则服务器返回新的响应header信息更新缓存中的对应header信息,但是并不返回资源内容,它会告知浏览器可以直接从缓存获取;否则返回最新的资源内容<a name="t3"></a>强缓存<p>强缓存是利用http的返回头中的Expires或者Cache-Control两个字段来控制的,用来表示资源的缓存时间。</p><p>Expires<br /> 该字段是http1.0时的规范,它的值为一个绝对时间的GMT格式的时间字符串,比如Expires:Mon,18 Oct 2066 23:59:59 GMT。这个时间代表着这个资源的失效时间,在此时间之前,即命中缓存。这种方式有一个明显的缺点,由于失效时间是一个绝对时间,所以当服务器与客户端时间偏差较大时,就会导致缓存混乱。</p><p>Cache-Control<br /> Cache-Control是http1.1时出现的header信息,主要是利用该字段的max-age值来进行判断,它是一个相对时间,例如Cache-Control:max-age=3600,代表着资源的有效期是3600秒。cache-control除了该字段外,还有下面几个比较常用的设置值:</p>no-cache:不使用本地缓存。需要使用缓存协商,先与服务器确认返回的响应是否被更改,如果之前的响应中存在ETag,那么请求的时候会与服务端验证,如果资源未被更改,则可以避免重新下载。no-store:直接禁止游览器缓存数据,每次用户请求该资源,都会向服务器发送一个请求,每次都会下载完整的资源。public:可以被所有的用户缓存,包括终端用户和CDN等中间代理服务器。private:只能被终端用户的浏览器缓存,不允许CDN等中继缓存服务器对其缓存。<p>Cache-Control与Expires可以在服务端配置同时启用,同时启用的时候Cache-Control优先级高。</p><a name="t4"></a>协商缓存<p>协商缓存就是由服务器来确定缓存资源是否可用,所以客户端与服务器端要通过某种标识来进行通信,从而让服务器判断请求资源是否可以缓存访问,这主要涉及到下面两组header字段,这两组搭档都是成对出现的,即第一次请求的响应头带上某个字段(Last-Modified或者Etag),则后续请求则会带上对应的请求字段(If-Modified-Since或者If-None-Match),若响应头没有Last-Modified或者Etag字段,则请求头也不会有对应的字段。</p><p>Last-Modify/If-Modify-Since</p><p>浏览器第一次请求一个资源的时候,服务器返回的header中会加上Last-Modify,Last-modify是一个时间标识该资源的最后修改时间,例如Last-Modify: Thu,31 Dec 2037 23:59:59 GMT。</p><p>当浏览器再次请求该资源时,request的请求头中会包含If-Modify-Since,该值为缓存之前返回的Last-Modify。服务器收到If-Modify-Since后,根据资源的最后修改时间判断是否命中缓存。</p><p>如果命中缓存,则返回304,并且不会返回资源内容,并且不会返回Last-Modify。</p><p>ETag/If-None-Match</p><p>与Last-Modify/If-Modify-Since不同的是,Etag/If-None-Match返回的是一个校验码。ETag可以保证每一个资源是唯一的,资源变化都会导致ETag变化。服务器根据浏览器上送的If-None-Match值来判断是否命中缓存。</p><p>与Last-Modified不一样的是,当服务器返回304 Not Modified的响应时,由于ETag重新生成过,response header中还会把这个ETag返回,即使这个ETag跟之前的没有变化。</p><p>为什么要有Etag</p><p>你可能会觉得使用Last-Modified已经足以让浏览器知道本地的缓存副本是否足够新,为什么还需要Etag呢?<a href="http://caibaojian.com/t/http" title="View all posts in HTTP" target="_blank">HTTP</a>1.1中Etag的出现主要是为了解决几个Last-Modified比较难解决的问题:</p>一些文件也许会周期性的更改,但是他的内容并不改变(仅仅改变的修改时间),这个时候我们并不希望客户端认为这个文件被修改了,而重新GET;某些文件修改非常频繁,比如在秒以下的时间内进行修改,(比方说1s内修改了N次),If-Modified-Since能检查到的粒度是s级的,这种修改无法判断(或者说UNIX记录MTIME只能精确到秒);某些服务器不能精确的得到文件的最后修改时间。<p>Last-Modified与ETag是可以一起使用的,服务器会优先验证ETag,一致的情况下,才会继续比对Last-Modified,最后才决定是否返回304。</p><p>强缓存与协商缓存的区别可以用下表来表示:</p>缓存类型获取资源形式状态码发送请求到服务器强缓存从缓存取200(from cache)否,直接从缓存取协商缓存从缓存取304(Not Modified)否,通过服务器来告知缓存是否可用<a name="t5"></a>用户行为对缓存的影响用户操作Expires/Cache-ControlLast-Modied/Etag地址栏回车有效有效页面链接跳转有效有效新开窗口有效有效前进回退有效有效F5刷新无效有效Ctrl+F5强制刷新无效无效<a name="t6"></a>实际问题分析<p>如文章开头所属,代码更新到线上后用户浏览器不能自行更新,我们不能要求客户在系统更新后都进行一次缓存清理的操作。</p><p>到底该如何解决呢?</p><p>在资源请求的URL中增加一个参数,比如:js/mian.js?ver=0.7.1。这个参数是一个版本号,每一次部署的时候变更一下,当这个参数变化的时候,强缓存都会失效并重新加载。这样一来,静态资源,部署以后就需要重新加载。这样就比较完美的解决了问题。</p><p>关于浏览器缓存,之前写过几篇,你也许感兴趣:</p><a href="http://caibaojian.com/http-cache-2.html">HTTP缓存策略</a><a href="http://caibaojian.com/http-cache.html" target="_blank">HTTP缓存是如何实现</a><a href="http://caibaojian.com/http-gzip.html" target="_blank">HTTP压缩,浏览器是如何解析的</a><p>本文转自:<a href="https://segmentfault.com/a/1190000005704489" target="_blank" rel="nofollow">浏览器缓存,想说爱你不容易</a></p>推荐文章<a href="http://caibaojian.com/http-cache-2.html" rel="bookmark">HTTP缓存策略</a><a href="http://caibaojian.com/http-cache.html" rel="bookmark">HTTP缓存是如何实现</a><a href="http://caibaojian.com/http-cache-3.html" rel="bookmark">HTTP基于缓存策略三要素分解法</a><a href="http://caibaojian.com/server-cache.html" rel="bookmark">服务器缓存的实现过程详解</a><br />来源:<a href="http://caibaojian.com/browser-cache.html">前端开发博客</a><br /><p><br /></p>

正文结束

阿里云、腾讯云 apache的vhost配置https 研发代码规范 2017.12.7 手写初版