HTTP缓存一直是一个老生常谈的问题,前端在平常发布、部署工做中,经常要面对。javascript
其中面对的问题有可能会是:部署的代码没法生效css
此次本人所在团队也遇到了相关问题,这里简述一下:html
项目会在静态资源(如:css,js)使用chunkHash来处理,所以能保证修改后与旧代码文件名字不会重复。以免没法更新改动。前端
在该项目中部署后,进行代码进行一次location.reload
,改动便可以生效。java
最后,本人发现是由于该项目部署的服务器上全部静态资源的response headers的设置以下:git
response headers:github
但致命的是,项目的入口: index.html也是如此。所以实际是由于全部的.html文件命中(cache hit)了强缓存,致使了用户没法直接呈现更新后代码的改动。web
找到了缘由,也想到了以下三个解决方案chrome
跳转时增长时间戳例如:浏览器
具体为何能够这么作在以后分析查看是否存在缓存步骤时会解析
location.href = 'https://www.localhost:5000.com/index.html?t=201811141248001';
复制代码
修改response headers中的cache-control
举例:
cache-control: public, max-age=0
复制代码
使用HTML Meta 标签
能够在html代码中增长meta标签:
<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" />
复制代码
上述代码的做用是告诉浏览器当前页面不被缓存,每次访问都须要去服务器拉取。使用上很简单,但只有部分浏览器能够支持,并且全部缓存代理服务器都不支持,由于代理不解析HTML内容自己。
最好仍是不要指定HTML标签,经过可能会出现混乱(到底以那端为主,实际response header的优先级更高)。此外,在HTML5中,这些<meta HTTP等>标签是无效的。只有HTML5规范中列出的HTTP等效值才被容许。
既然找到问题了,我以为那我就顺藤摸瓜的总结一下吧。
HTTP 缓存:重用已获取的资源可以有效的提高网站与应用的性能。Web 缓存可以减小延迟与网络阻塞,进而减小显示某个资源所用的时间。借助 HTTP 缓存,Web 站点变得更具备响应性。
HTTP 缓存分为:强缓存和协商缓存
其中关键步骤是:
浏览器怎么断定是否存在本地缓存,这个步骤在此能够理解为浏览器去查找本地是否存在该响应请求的文件存在,查找是不是否有该对应的请求,不一样浏览器缓存文件的地址也不尽相同。
以firefox举例,能够在地址栏输入:about:cache
P.S: chrome://cache
在 chrome66版本后已废弃。
如图上所示,这里咱们能够看到浏览器关于网络请求缓存的一些信息。咱们以本地磁盘中的为例子。
如图上所示,在此咱们能够查看到一些关于缓存在磁盘内的信息,包括实际本地缓存所在的位置等。
如上图,这就是一次响应请求的文件,而且他会记录完整的url包括:query string。
如上两图所见,咱们改变了t参数的值,实际咱们在url后打时间戳来规避命中缓存,实际就是在此改变了查询URL,让浏览器没法查询到与以前请求相同的本地缓存。
最后能够看到,咱们的本地缓存文件内,会包含response-head的信息,以后的缓存策略和流程都须要依赖此处的信息。
总结一下,查看是否存在缓存的过程实际就是查找响应请求文件是否存在。
强制缓存就是向浏览器缓存查找该请求结果,并根据该结果的缓存规则来决定是否使用该缓存结果的过程。
实际就是咱们总体流程内的,查看是否存在缓存以及,查看缓存是否有效。
实现强缓存,主要是根据客户端保留的一个服务器端的response header中的两个字段:expires
、cache-control
。
cache-control
优先级比expires
高。
如图:
图中可知二者的区别
HTTP响应报文中expires的时间值,是一个绝对值。
HTTP响应报文中Cache-Control为max-age=31536000,是相对值。
在没法肯定客户端的时间是否与服务端的时间同步的状况下,Cache-Control相比于expires是更好的选择,因此同时存在时,只有Cache-Control生效。
Expires
Expires是HTTP/1.0控制网页缓存的字段,其值为服务器返回该请求结果缓存的到期时间,即再次发起该请求时,若是客户端的时间小于Expires的值时,直接使用缓存结果。
Expires: Wed, 21 Oct 2015 07:28:00 GMT
复制代码
Cache-Control
在HTTP/1.1中,Cache-Control是最重要的规则,主要用于控制网页缓存,列几个常见的值:
public:全部内容都将被缓存(客户端和代理服务器均可缓存)
private:全部内容只有客户端能够缓存,Cache-Control的默认取值
no-cache:客户端缓存内容,可是是否使用缓存则须要通过协商缓存来验证决定
no-store:全部内容都不会被缓存,即不使用强制缓存,也不使用协商缓存
max-age=xxx (xxx is numeric):缓存内容将在xxx秒后失效
Cache-Control:public, max-age=31536000
复制代码
判断缓存是否过时的流程的流程:
缓存失效时间计算公式以下:
expirationTime = responseTime + freshnessLifetime - currentAge
复制代码
在上面这个公式里,responseTime
表示浏览器接收到此响应的那个时间点。
状态码为灰色的请求则表明使用了强制缓存,请求对应的Size值则表明该缓存存放的位置
至于from memory cache 和 from disk cache相关的以后讲解。
协商缓存就是强制缓存失效后,浏览器携带缓存标识向服务器发起请求,由服务器根据缓存标识决定是否使用缓存的过程。
协商缓存的标识也是在响应报文的HTTP头中和请求结果一块儿返回给浏览器的,控制协商缓存的字段分别有:Last-Modified / If-Modified-Since
和 Etag / If-None-Match
。
Etag / If-None-Match
优先级比 Last-Modified / If-Modified-Since
高。
Last-modified:
Last-Modified是服务器响应请求时,返回该资源文件在服务器最后被修改的时间
Last-Modified: Wed, 21 Oct 2015 07:28:00 GMT
复制代码
If-Modified-Since:
If-Modified-Since: Wed, 21 Oct 2015 07:28:00 GMT
复制代码
Etag:
Etag是服务器响应请求时,返回当前资源文件的一个惟一标识(由服务器生成)
ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4"
ETag: W/"0815"
复制代码
If-None-Match:
If-None-Match是客户端再次发起该请求时,携带上次请求返回的惟一标识Etag值,经过此字段值告诉服务器该资源上次请求返回的惟一标识值。服务器收到该请求后,发现该请求头中含有If-None-Match,则会根据If-None-Match的字段值与该资源在服务器的Etag值作对比,一致则返回304,表明资源无更新,继续使用缓存文件;不一致则从新返回资源文件,状态码为200
If-None-Match: "33a64df551425fcc55e4d42a148795d9f25f89d4"
复制代码
而后咱们看一下具体流程:
若是协商缓存命中,请求响应返回的http状态为304而且会显示一个Not Modified的字符串。
二者的共同点是:若是命中,都是从客户端缓存中加载资源,而不是从服务器加载资源数据;
二者的区别是:强缓存不发请求到服务器,协商缓存会发请求到服务器。
其实浏览器的相关操做,会对开发人员理解浏览器HTTP缓存产生一些影响,所以咱们详细来分析一下:
在Alloy Team的Web缓存机制系列中有总结:
Web缓存机制系列2 – Web浏览器的缓存机制 - Alloy Team
浏览器相关操做 | Expires/Cache-Control | Last-Modified / Etag |
---|---|---|
地址栏回车 | 有效 | 有效 |
页面连接跳转 | 有效 | 有效 |
新开窗口 | 有效 | 有效 |
前进、后退 | 有效 | 有效 |
刷新 | 无效 | 有效 |
强制刷新 | 无效 | 无效 |
这块我想梳理一下,与你们分享以及验证一下:
测试前提:
测试的浏览器为:
测试影响的文件:
测试使用的response header的设置为:
Chrome 70测试结果:
如图:
结果:
Firefox 63.0.1 测试结果:
如图:
结果:
Opera 56.0 测试结果:
如图:
结果:
Chrome 70测试(因为默认为google页,采用了隐私模式测试)结果:
如图:
结果:
Firefox 63.0.1 测试结果:
如图:
结果:
Opera 56.0(隐私模式) 测试结果:
如图:
结果:
Chrome 70测试结果:
如图:
结果:
Firefox 63.0.1 测试结果:
如图:
结果:
Opera 56.0 测试结果:
如图:
结果:
刷新这一块是测试的重点(以前正由于)
Chrome 70测试结果:
如图:
结果:
Firefox 63.0.1 测试结果:
如图:
结果:
Opera 56.0 测试结果:
如图:
结果:
这个部分还得分红从当前tab回车和从另外一url
至关于页面连接跳转
至关于刷新
Firefox 63.0.1 测试结果:
至关于页面连接跳转
至关于页面连接跳转
Opera 56.0 测试结果:
至关于刷新
Chrome 70测试结果:
如图:
结果:
Firefox 63.0.1 测试结果:
如图:
结果:
index.html:从服务器端获取资源
index.js:从服务器端获取资源
index.css:从服务器端获取资源
doge.jpeg:从服务器端获取资源
favicon.ico:从服务器端获取资源
Opera 56.0 测试结果:
如图:
结果:
虽然费了那么大力气测试,最终结论只是稍微调整了一下:
浏览器相关操做 | Expires/Cache-Control | Last-Modified / Etag |
---|---|---|
页面连接跳转 | 有效 | 有效 |
新开窗口 | 有效 | 有效 |
前进、后退 | 有效 | 有效 |
刷新 | chrome opera html无效 ico文件无效, ff有效 |
chrome opera ico文件无效, ff有效 |
地址栏回车 | 当前URL回车 - chrome opera同刷新 当前URL回车 - ff同刷新 其余URL回车 - 同页面连接跳转 |
当前URL回车 - chrome opera同刷新 当前URL回车 - ff同刷新 其余URL回车 - 同页面连接跳转 |
强制刷新 | 无效 | 无效 |
图片引用自:Web缓存机制系列2 – Web浏览器的缓存机制
总结了一个相对完成的流程图:
这部分没有实际实践过,只是摘选了部分文章的观点:
分布式系统里多台服务器间的文件的Last-Modified必须保持一致,以避免负载均衡到不一样服务器致使对比结果不一致。
分布式系统尽可能关闭掉ETag(每台机器生成的ETag都会不同,淘宝页面中的静态资源response headers中都没有ETag)。
这个部分目前暂时没有找到十分的标准答案或文档,目前我仅将本身梳理过的部分知识记录在案:
其实webkit缓存机制还有一个叫 pageCache 这里暂不讨论:WebKit Page Cache I – The Basics
Chrome使用两个缓存: disk cache
和 memory cache
如下例子都仅针对Chrome
从磁盘中获取缓存资源,等待下次访问时不须要从新下载资源,而直接从磁盘中获取。
从内存中获取资源,等待下次访问时不须要从新下载资源,而直接从内存中获取。Webkit早已支持memoryCache。
测试条件与上文其余测试相同:
能够得出一个基本**“现象”**:
memory cache的生命周期于tabs的选项卡大体对应。
The lifetime of an in-memory cache is attached to the lifetime of a render process, which roughly corresponds to a tab.
能够参考:developer.chrome - webRequest
有见过一种论点:
目前Webkit资源分红两类:
主资源
主资源: 经过MainResourceLoader
加载,如HTML页面,或者下载项等
派生资源
派生资源:,经过 SubresourceLoader
加载,好比HTML页面中内嵌的图片或者脚本连接
虽然Webkit支持memoryCache,可是也只是针对派生资源,它对应的类为CachedResource,用于保存原始数据(好比CSS,JS等),以及解码过的图片数据。
此图所示:
好像并不适用,彻底适用css第一次并无,从 memory cache 加载,
可是通过几回,后退从新跳转后(不定次数):
到此,以本人的能力可能暂时,没法做出一个比较好的解答了,但愿以后有大佬能够给到一个解答。
MDN HTTP 缓存:
Web缓存机制系列2 Web浏览器的缓存机制:
W3 HTML spec chapter 5.2.2:
Stackoverflow how-to-control-web-page-caching-across-all-browsers:
Stackoverflow how-chrome-browser-determine-memory-cache-and-disk-cache:
developer.chrome.com webRequest: