幻滅 發表於 2021-8-20 11:47:11

基于HTTP浏览器缓存机制全面解析

<div id="navCategory"><h5 class="catalogue">目录</h5><ul class="first_class_ul"><li><a href="#_label0">什么是浏览器缓存</a></li><li><a href="#_label1">非HTTP协议定义的缓存机制</a></li><li><a href="#_label2">缓存流程图</a></li><li><a href="#_label3">HTTP缓存机制</a></li><li><a href="#_label4">服务端如何判断缓存已失效</a></li><ul class="second_class_ul"><li><a href="#_lab2_4_0">Last-Modified/If-Modified-Since</a></li><li><a href="#_lab2_4_1">Etag/If-None-Match</a></li></ul><li><a href="#_label5">为什么有了Last-Modified还要Etag&#63;</a></li><ul class="second_class_ul"></ul><li><a href="#_label6">200 OK(from cache)与304 Not Modified的区别</a></li><ul class="second_class_ul"><li><a href="#_lab2_6_2">200 OK( from cache ) 出现操作:</a></li><li><a href="#_lab2_6_3">304 Not Modified 出现操作:</a></li></ul><li><a href="#_label7">缓存的不同来源</a></li><ul class="second_class_ul"></ul><li><a href="#_label8">不能被缓存的请求</a></li><ul class="second_class_ul"></ul></ul></div><p class="maodian"><a name="_label0"></a></p><h2>什么是浏览器缓存</h2>
<p>Web缓存是指一个Web资源(如html页面,图片,js,数据等)存在于Web服务器和客户端(浏览器)之间的副本。缓存会根据进来的请求保存输出内容的副本;当下一个请求来到的时候,如果是相同的URL,缓存会根据缓存机制决定是直接使用副本响应访问请求,还是向源服务器再次发送请求。</p>
<p>比较常见的就是浏览器会缓存访问过网站的网页,当再次访问这个URL地址的时候,如果网页没有更新,就不会再次下载网页,而是直接使用本地缓存的网页。</p>
<p>只有当网站明确标识资源已经更新,浏览器才会再次下载网页。浏览器和网站服务器是根据缓存机制进行缓存的</p>
<p class="maodian"><a name="_label1"></a></p><h2>非HTTP协议定义的缓存机制</h2>
<p>浏览器缓存机制,其实主要就是HTTP协议定义的缓存机制(如: Expires; Cache-control等)。但是也有非HTTP协议定义的缓存机制,如使用HTML Meta 标签,Web开发者可以在HTML页面的节点中加入标签</p>
<div class="jb51code">
<pre class="brush:xhtml;">
&lt;meta http-equiv="Pragma" content="no-cache"&gt;</pre>
</div>
<p>上述代码的作用是告诉浏览器当前页面不被缓存,每次访问都需要去服务器拉取。使用上很简单,但只有部分浏览器可以支持,而且所有缓存代理服务器都不支持,因为代理不解析HTML内容本身。</p>
<p class="maodian"><a name="_label2"></a></p><h2>缓存流程图</h2>
<p>利用浏览器缓存的过程:</p>
<p><img alt="在这里插入图片描述" src="https://img.jbzj.com/file_images/article/202108/2021082011371613.png" /></p>
<p class="maodian"><a name="_label3"></a></p><h2>HTTP缓存机制</h2>
<p>根据Response Header里面的Cache-Control和Expires这两个属性,当两个都存在时,Cache-Control优先级较高。</p>
<p><code>Cache-Control</code></p>
<p style="text-align: center"><font face="NSimsun"><img alt="在这里插入图片描述" src="https://img.jbzj.com/file_images/article/202108/2021082011371614.png" /> </font></p>
<p>该字段用于控制浏览器在什么情况下直接使用本地缓存而不向服务器发送请求。一般具有以下值:</p>
<ul>
    <li><code>Public</code>:指示响应可被任何缓存区缓存。</li>
    <li><code>Private</code>:指示对于单个用户的整个或部分响应消息,不能被共享缓存处理。这允许服务器仅仅描述当用户的部分响应消息,此响应消息对于其他用户的请求无效。</li>
    <li><code>no-cache</code>:指示请求或响应消息不能缓存。</li>
    <li><code>no-store</code>:用于防止重要的信息被无意的发布。在请求消息中发送将使得请求和响应消息都不使用缓存。</li>
    <li><code>max-age</code>:指示浏览器可以接收生存期不大于指定时间(<strong>以秒为单位</strong>)的响应。</li>
    <li><code>min-fresh</code>:指示浏览器可以接收响应时间小于当前时间加上指定时间的响应。</li>
    <li><code>max-stale</code>:指示浏览器可以接收超出超时期间的响应消息。如果指定max-stale消息的值,那么浏览器可以接收超出超时期指定值之内的响应消息。</li>
</ul>
<p><code>Expires(石器时代的缓存机制)</code></p>
<p>Expires 头部字段提供一个日期和时间,在该日期前的所有对该资源的请求都会直接使用浏览器缓存而不用向服务器请求。</p>
<p>例如:Expires: Sun, 08 Nov 2009 03:37:26 GMT</p>
<p>注意:</p>
<ul>
    <li>cache-control max-age 和 max-stale将覆盖Expires header。</li>
    <li>使用Expires存在服务器端时间和浏览器时间不一致的问题。</li>
    <li>另外有人说Expires 是HTTP 1.0的东西,现在默认浏览器均默认使用HTTP 1.1。</li>
</ul>
<p class="maodian"><a name="_label4"></a></p><h2>服务端如何判断缓存已失效</h2>
<p>服务端通过If-Modified-Since(Last-Modified)和If-None-Match(Etag)这两个属性的值来判断缓存是否失效的。</p>
<p class="maodian"><a name="_lab2_4_0"></a></p><h3>Last-Modified/If-Modified-Since</h3>
<p>Last-Modified/If-Modified-Since要配合Cache-Control使用。</p>
<p><code>Last-Modified</code>:响应资源的最后修改时间。</p>
<p><code>If-Modified-Since</code>:当缓存过期时,发现资源具有Last-Modified声明,则在请求头带上If-Modified-Since(值就是Last-Modified)。服务器收到请求后发现有头If-Modified-Since则与被请求资源的最后修改时间进行比对。若最后修改时间较新,说明资源又被改动过,则响应HTTP 200整片资源内容(写在响应消息包体内);若最后修改时间较旧,说明资源无新修改,则响应HTTP 304,告知浏览器继续使用所保存的cache。</p>
<p class="maodian"><a name="_lab2_4_1"></a></p><h3>Etag/If-None-Match</h3>
<p>Etag/If-None-Match也要配合Cache-Control使用。</p>
<p><code>Etag</code>:资源在服务器的唯一标识(生成规则由服务器决定)。Apache中,ETag的值,默认是对文件的索引节(INode),大小(Size)和最后修改时间(MTime)进行Hash后得到的。</p>
<p><code>If-None-Match</code>:当缓存过期时,发现资源具有Etage声明,则在请求头带上If-None-Match(值就是Etag)。服务器收到请求后发现有头If-None-Match 则与被请求资源的相应校验串进行比对,决定返回200或304。</p>
<p class="maodian"><a name="_label5"></a></p><h2>为什么有了Last-Modified还要Etag&#63;</h2>
<p>Etag的出现主要是为了解决几个Last-Modified比较难解决的问题:</p>
<ul>
    <li>Last-Modified标注的最后修改只能精确到秒级,如果某些文件在1秒钟以内,被修改多次的话,它将不能准确标注文件的修改时间。</li>
    <li>如果某些文件会被定期生成,当有时内容并没有任何变化,但Last-Modified却改变了,导致文件没法使用缓存。</li>
    <li>有可能存在服务器没有准确获取文件修改时间,或者与代理服务器时间不一致等情形。</li>
</ul>
<p class="maodian"><a name="_label6"></a></p><h2>200 OK(from cache)与304 Not Modified的区别</h2>
<p>200 OK( from cache )不向服务器发送请求,直接使用本地缓存文件。304 Not Modified则向服务器询问,若服务器认为浏览器的缓存版本还可用,那么便会返回304。</p>
<p class="maodian"><a name="_lab2_6_2"></a></p><h3>200 OK( from cache ) 出现操作:</h3>
<p>1.地址栏回车</p>
<p>2.页面链接跳转</p>
<p>3.前进、后退</p>
<p class="maodian"><a name="_lab2_6_3"></a></p><h3>304 Not Modified 出现操作:</h3>
<p>1.F5刷新</p>
<p>2.新开窗口</p>
<p class="maodian"><a name="_label7"></a></p><h2>缓存的不同来源</h2>
<p><code>from disk cache</code>:从磁盘中获取缓存资源,等待下次访问时不需要重新下载资源,而直接从磁盘中获取。它的直接操作对象为CurlCacheManager。</p>
<p><code>from memory cache</code>:从内存中获取资源,等待下次访问时不需要重新下载资源,而直接从内存中获取。</p>
<p><strong>两者区别:</strong>当退出进程时,内存中的数据会被清空,而磁盘的数据不会,所以,当下次再进入该进程时,该进程仍可以从diskCache中获得数据,而memoryCache则不行。</p>
<p class="maodian"><a name="_label8"></a></p><h2>不能被缓存的请求</h2>
<p>当然并不是所有请求都能被缓存。</p>
<p>无法被浏览器缓存的请求:</p>
<ul>
    <li>HTTP信息头中包含Cache-Control:no-cache,pragma:no-cache(HTTP1.0),或Cache-Control:max-age=0等告诉浏览器不用缓存的请求</li>
    <li>需要根据Cookie,认证信息等决定输入内容的动态请求是不能被缓存的</li>
    <li>经过HTTPS安全加密的请求</li>
    <li>POST请求无法被缓存</li>
    <li>HTTP响应头中不包含Last-Modified/Etag,也不包含Cache-Control/Expires的请求无法被缓存</li>

</ul>
<p>以上为个人经验,希望能给大家一个参考,也希望大家多多支持琼殿技术社区。</p>
頁: [1]
查看完整版本: 基于HTTP浏览器缓存机制全面解析