浏览器缓存机制
什么是浏览器缓存:
简单来说:浏览器缓存就是把一个已经请求过的web资源(如html页面,图片,js,数据等)拷贝一份副本储存在浏览器中,缓存会根据进来的请求保存输出内容的副本。当下一个请求来到的时候,如果是相同的URL,缓存会根据缓存机制决定是直接使用副本响应访问请求,还是想资源服务器再次发送请求。比较常见的就是浏览器会缓存访问过的网站的网页,当再次访问这个URL地址的时候,如果网页没有更新们就不会再次下载网页,而是直接使用本地缓存的网页。 只有当网站明确标识资源已经更新,浏览器才会再次下载网页。
为什么使用缓存:
1.减少对于网站带宽消耗:
无论是对于网站运营商或者用户,带宽都代表着金钱,过多的带宽消耗,只会便宜了网络运营商。当WEB缓存副本被使用时,只会产生极小的网络浏量,可以有效降低运营成本。
2.降低服务器的压力
给网络资源设定有效期后,用户可以重复使用本地缓存,减少对资源服务器的请求,简介降低服务器的压力。
3.减少网络延迟,加快页面打开速度
缓存能够明显加快页面的打开速度达到更好的体验。
缓存过程分析:
浏览器与服务器通信的方式为应答模式,即是:浏览器发起HTTP请求-服务器响应该请求。那么浏览器第一次向服务器发送请求后拿到的请求结果,会根据应报文中http的缓存标识,决定是否缓存结果,是则将请求结果和缓存标识存入浏览器中。
第一次发起http请求由此可得:
1.浏览器每次发送请求,都会先在浏览器缓存中查找该请求的结果以及缓存标识。
2.浏览器每次拿到返回的请求结果都会将结果和缓存标识存入浏览器缓存中
以上两点结论就是浏览器缓存机制的关键,他确保了每次请求的缓存存入与读写。根据是否需要想服务器重新发送http请求缓存过程分为两个部分,分别是强缓存和协商缓存。
强制缓存
强制缓存就是向浏览器查找该请求结果,并根据该结果的缓存规则来决定是否使用缓存结果的过程,强制缓存的情况主要分三种: 如下
1.不存在该缓存结果和缓存标识,强制缓存失败,则直接向服务器发起请求(跟第一次发送请求一致)
不存在该缓存结果和缓存标识.2.存在该缓存结果和缓存标识,但该结果已失效,强制缓存失效,则使用协商缓存
存在该缓存结果和缓存标识,但该结果已失效3.存在该缓存结果和缓存标识,且该结果尚未失效,直接返回该结果。
存在该缓存结果和缓存标识,且该结果尚未失效强制缓存的规则?
当浏览器向服务器发送请求时,服务器会将缓存规则放入HTTP响应报文的HTTP头中和请求结果一起返回给浏览器,控制强制缓存的字段分别是Expires和Cache-Control,其中Cache-Control优先级比Expires高。
Expires
Expires是HTTP/1.0控制网页缓存的字段,其值为服务器返回该请求结果缓存的到期时间,即再次发起该请求时,如果客户端的时间晓宇Expires的值,直接使用缓存结果
Expires是HTTP/1.0的字段,但是现在浏览器默认使用的是HTTP/1.1,那么再HTTP/1.1中网页缓存还是否又Expires控制?
到了HTTP/1.1,Expires已经被Cache-Control替代,原因再于Expires控制缓存的原理是使用客户端的时间与服务器返回分时间做对比,那么如果客户端的时间因为某些原因发生误差,那么强制缓存则会直接失效,这样的话强制缓存的存在则毫无意义,那么Cache-Control又是如何控制的呢?
Cache-Control
在HTTP/1.1中,Cache-Control是最重要的规则,只要控制网页的缓存,主要取值为:
·public: 所以内容都将被缓存(客户端和代理服务器都可缓存)
·private:所有内容只有客户端可以缓存,Cache-Control的默认取值
·no-cache:客户端缓存内容,但是是否使用缓存则需要经过协商缓存来验证决定。
·no-store:所有内容都不会被缓存,即不使用强制缓存,也不使用协商缓存
·max-age=xxx(xxx is numeric):缓存内容将在XXX秒后失效
由上图可知:
HTTP响应报文中expires的时间值,是一个绝对值
HTTP响应报文中Cache-Control为max-age=3153600,是相对值
由于Cache-Control的优先级比expires高,那么直接根据Cache-Control的值进行缓存,意思说在3153600秒内再次发起请求,则会直接使用缓存结果,强制缓存生效。
注:在无法确定客户端的时间是否于服务端的时间同步的情况下,Cache-Control相比于expires是更好的选中,所以同事存在时只有Cache-Control生效。
***
浏览器的缓存存放在哪里,如何在浏览器中判断强制缓存是否生效?
状态码为灰色的请求则代表使用了强制缓存,请求对应得Size值代表该缓存存放得位置,分别为from memory cache和from disk cache
from memory cache和from disk cache又分别代表什么呢?什么时候会使用from memory cache,什么时候会使用from disk cache呢?
from memory cache代表使用内存中得缓存
from disk cache代表使用得时硬盘中得缓存,浏览器读取缓存得顺序为memory -》 disk
访问https://www.jianshu.com/p/e59d16a9ab7e -》200
-》关闭标签页 -》重新打开https://www.jianshu.com/p/e59d16a9ab7e -》 200(from disk cache)-》 刷新-》 200(from memory cache)
过程如下
访问https://www.jianshu.com/p/e59d16a9ab7e
第一次打开关闭标签页
重新打开https://www.jianshu.com/p/e59d16a9ab7e
关闭标签页再打开刷新:
刷新最后一次(刷新)同时存在from disk cache和from memory cache
对于这个问题,需要了解以下 内存缓存(from memory cache)和硬盘缓存(from disk cache)
内存缓存(from memory cache):内存缓存又两个特点,分别是快速读取和
快速读取: 内存缓存会将编译解析后得文件,,直接存入该进程得内存中,占据该进程一定得内存资源,以方便下次允许使用时得快速读取
时效性:一旦该进程关闭,则该进程得内存则会清空。
硬盘缓存(from disk cache):硬盘缓存则是直接将缓存写入硬盘文件中,读取缓存需要对该缓存存放得硬盘文件进行I/O操作,然后重新解析该缓存内容,读取赋值,速度比内存缓存慢。
在浏览器中,浏览器会将js和图片等文件解析执行后直接存入内存缓存中,那么当刷新页面只需直接从内存缓存中读取(from memory cache);而css文件则会存入硬盘文件中,所以每次渲染都需要从硬盘读取缓存(from disk cache)
协商缓存:
协商缓存就是强制缓存失效后,浏览器携带缓存标识向服务器发送请求,有服务器根据缓存标识决定是否使用缓存过程,主要有以下两种情况:
·协商缓存生效,返回304,如下
协商缓存生效协商缓存失效,返回200和请求结果,如下
协商缓存失效同样,协商缓存得标识也是在响应报文得HTTP头中和请求结果一起返回给浏览器的,控制协商缓存的字段分别有:Last-Modified / If-Modified-Since和Etag / If-None-Match,其中Etag / If-None-Match的优先级比Last-Modified / If-Modified-Since高
Last-Modified / If-Modified-Since
Last-Modified是服务器响应请求时,返回该资源文件在服务器最后被修改的时间,如下。
Last-ModifiedIf-Modified-Since则是客户端再次发起该请求时,携带上次请求返回的Last-Modified值,通过此字段值告诉服务器该资源上次请求返回的最后被修改时间。服务器收到该请求,发现请求头含有If-Modified-Since字段,则会根据If-Modified-Since的字段值与该资源在服务器的最后被修改时间做对比,若服务器的资源最后被修改时间大于If-Modified-Since的字段值,则重新返回资源,状态码为200;否则则返回304,代表资源无更新,可继续使用缓存文件,如下。
Etag / If-None-Match
Etag是服务器响应请求时,返回当前资源文件的一个唯一标识(由服务器生成),如下
If-None-Match是客户端再次发起该请求时,携带上次请求返回的唯一标识Etag值,通过此字段值告诉服务器该资源上次请求返回的唯一标识值。服务器收到该请求后,发现该请求头中含有If-None-Match,则会根据If-None-Match的字段值与该资源在服务器的Etag值做对比,一致则返回304,代表资源无更新,继续使用缓存文件;不一致则重新返回资源文件,状态码为200,如下。
注:Etag / If-None-Match优先级高于Last-Modified / If-Modified-Since,同时存在则只有Etag / If-None-Match生效。
总结:
强制缓存优先于协商缓存,若强制缓存(EXpires和Cache-Control)生效则直接使用强制缓存,若不生效则进行协商缓存(Last-Modified / If-Modified-Since和Etag / If-None-Match),协商缓存有服务器决定是否使用缓存,若协商缓存失效,那么代表请求的缓存失效,重新呼气请求结果,在存入浏览器缓存中,生效则返回304,继续使用缓存,主要过程如下:
实际场景应用缓存策略
1.频繁变动的资源
Cache-Control: no-cache
对于频繁变动的资源,首先需要使用Cache-Control: no-cache 使浏览器每次都请求服务器,然后配合 ETag 或者 Last-Modified 来验证资源是否有效。这样的做法虽然不能节省请求数量,但是能显著减少响应数据大小。
2.不常变化的资源
Cache-Control: max-age=31536000
通常在处理这类资源时,给它们的 Cache-Control 配置一个很大的max-age=31536000(一年),这样浏览器之后请求相同的 URL 会命中强制缓存。而为了解决更新的问题,就需要在文件名(或者路径)中添加 hash, 版本号等动态字符,之后更改动态字符,从而达到更改引用 URL 的目的,让之前的强制缓存失效 (其实并未立即失效,只是不再使用了而已)。
在线提供的类库 (如jquery-3.3.1.min.js,lodash.min.js等) 均采用这个模式
HTML
通过添加<meta>标签来禁止浏览器缓存(代码必须包含在<head>标签中)
<meta http-equiv='Cache-control' content='no-cache, no-store, must-revalidate' />
<meta http-equiv='Pragma' content='no-cache' />
<meta http-equiv='Expires' content='0'>
通过添加<meta>标签来设置止浏览器缓存(代码必须包含在<head>标签中)
<meta http-equiv="Cache-Control" content="max-age=7200" />
<meta http-equiv="Expires" content="Mon, 20 Jul 2019 23:00:00 GMT" />
缓存情况下前端代码部署
问题一:有了缓存,如何进行前端代码更新呢?
我们可以在资源文件或者图片后面添加版本号,如下图
问题二:但是所有文件都加了版本号之后,我们只更改了一个文件,其他文件的缓存不是浪费了吗?
解决这个问题,我们可以用数据摘要算法,对文件求摘要信息,摘要信息与文件内容一一对应。如下图:
html5缓存的更新问题:
方法有三种:
1、用户清除了离线存储的数据,这个不一定就是清理浏览器历史记录就可以做到的,因为不同浏览器管理离线存储的方式不同。比如Firefox的离线存储数据要到“选项”=>“高级”=>“网络”=>“脱机存储”里才可以清除。
2、manifest文件被修改,上面说的,你修改了manifest文件里所罗列的文件也不会更新缓存,而是要替换manifest文件//修改注释更新# wanz app v1
3、使用JavaScript api编写更新程序
方法12为自动更新,方法3为手动更新
1varappCache = window.applicationCache;
2appCache.update();// 开始更新
(appCache.status == window.applicationCache.UPDATEREADY) {
appCache.swapCache();//得到最新版本缓存列表,并且成功下载资源,更新缓存到最新
}
本文摘自以下几篇文章: