HTTP缓存机制
缓存就是数据交换的缓冲区,称作Cache,是临时存储数据的地方。其本质是以空间换时间。当用户需要数据时,会先在缓存中寻找,若是缓存中没有则再向服务器请求数据。这样的好处就是降低了传送数据的成本,减轻了服务器的压力,最直观的体现就是页面更快了。
HTTP缓存机制就是配置服务器响应头来告诉浏览器是否应该缓存资源、是否强制校验缓存以及缓存多长时间;浏览器非首次请求根据响应头是否应该取缓存、发送请求头验证缓存是否可用还是重新获取资源的过程。主要针对如css,js,图片等更新概率不大的静态文件。在浏览器中,浏览器会在js和图片等文件解析执行后直接存入内存缓存中,那么当刷新页面时只需直接从内存缓存中读取(from memory cache);而css文件则会存入硬盘文件中,所以每次渲染页面都需要从硬盘读取缓存(from disk cache)
下图是浏览器第一次获取数据的请求情况,在下图中将缓存单独拿出是为了更好的显示浏览器获取数据是怎样的一个流程,实际情况应该是浏览器会在本地的内存及磁盘种存储数据。
缓存规则告诉了浏览器如何处理缓存。浏览器向服务器请求数据时,会发送请求报文,服务器向浏览器返回数据,返回响应报文,报文主要分为header和body两个部分,与缓存相关的规则信息,均包含在header中。
在上图客户端第一次向服务器请求数据后,服务器返回数据以及缓存规则,缓存规则主要是在响应报文中的header中,具体的则是以响应字段以及值来规定的。 这里以浏览器再次请求数据缓存命中时是否需要向服务器发送请求为区别,将HTTP缓存规则分为强制缓存和对比缓存两类。
强制缓存
Expires:
Expires的值为服务端返回的到期时间,即下一次请求时,请求时间小于服务器返回的到期时间,直接使用缓存。不过Expires是HTTP1.0的东西,现在默认浏览器均默认使用HTTP1.1,所以它的作用基本忽略。另一个问题是,到期时间是由服务端生成的,客户端时间和服务端时间由误差,这就会导致缓存命中的误差。
Cache-Control:
no-store:明确告诉浏览器禁止缓存资源。
no-cache:告诉浏览器、缓存服务器,不管本地副本是否过期,使用资源前都需要到源服务器进行副本有效性校验。
max-age: 浏览器接受响过了xxx毫秒失效,优先级高于Expires。
public:表示一些中间代理、CDN等可以缓存资源。即便带有一些敏感HTTP验证身份信息甚至响应状态代码通常无法缓存的也可以缓存。
private:明确告知此资源只能单个用户可以缓存,其他中间代理不能缓存。原始发起的浏览器可以缓存,中间代理不能缓存。若未设置则默认private。
must-revalidate:缓存必须在使用之前验证旧资源的状态,并且不可使用过期资源.
s-maxage:覆盖max-age 或者 Expires 头,但是仅适用于共享缓存(比如各个代理),并且私有缓存中它被忽略。
no-transform:不得对资源进行转换或转变。Content-Encoding, Content-Range, Content-Type等HTTP头不能由代理修改。例如,非透明代理可以对图像格式进行转换,以便节省缓存空间或者减少缓慢链路上的流量。 no-transform指令不允许这样做。
对比缓存
Last-Modified/If-Modified-Since:
Last-Modified:
服务器在响应请求时,告诉浏览器资源的修改时间。

If-Modified-Since:
再次请求服务器的时候,通过此字段通知服务器上次请求时,服务器返回的资源最后修改时间。
服务器收到后会将If-Modified-Since的值与对应资源的最后修改时间进行对比。
若资源最后修改时间大于If-Modified-Since,说明资源又被改动过,则返回所需要的数据,返回状态码200。
若资源的最后修改时间小于或等于If-Modified-Since,说明资源无新修改,则响应304,告知浏览器可以继续使用Cache中的数据。
问题:Last-Modified只能精确到秒,假设文件是在1s内发生变动,Last-Modified无法感知到变化,这种情况下浏览器永远拿不到最新的文件。
Etag/If-None-Match:
Etag:
服务器响应请求时,告诉浏览器当前资源在服务器的唯一标识符(生成规则由服务器决定)。
If-None-Match:
再次请求时,通过此字段通知服务器客户端缓存数据的唯一标识符。
服务器收到后会与被请求资源的标识符进行对比,如果不同说明资源被修改过,返回新的数据内容,返回状态码200;
否则说明数据没有被修改过,响应HTTP304,告知浏览器可以继续使用Cache中的数据。
小结
md5/hash缓存
以上提到的缓存机制都是在判断MAX-age过期之后,再向服务器验证资源的有效性,但在MAX-age规定的时间内,资源被更改后,客户端是无法立即得知的。可以通过不缓存html,为静态文件添加MD5或者hash标识的方法,解决浏览器无法跳过缓存过期时间主动感知文件变化的问题。
之前服务器与浏览器的文件修改对比,文件标识对比的前提都是建立在两者文件路径完全相同的情况下,例如js/a-hash1.js与js/a-hash2.js是两个完全不同的文件,浏览器第一次加载页面,请求并缓存了js/a-hash1.js,第二次加载时文件指向变成了js/a-hash2.js,浏览器会重新请求a-hash2.js文件。通过这种办法,可以从根本上解决过期时间没到浏览器无法主动请求服务器的问题,因此我们需要在项目每次发布迭代将修改过的的静态文件添加不同的MD5或者hash标识。
不能缓存的请求:
1.HTTP信息头中包含Cache-Control:no-cache,pragma:no-cache(HTTP1.0),或Cache-Control:max-age=0等告诉浏览器不用缓存的请求。
2.需要根据Cookie,认证信息等决定输入内容的动态请求是不能被缓存的。
3.经过HTTPS安全加密的请求(有人也经过测试发现,ie其实在头部加入Cache-Control:max-age信息,firefox在头部加入Cache-Control:Public之后,能够对HTTPS的资源进行缓存)
4.POST请求无法被缓存。
5.HTTP响应头中不包含Last-Modified/Etag,也不包含Cache-Control/Expires的请求无法被缓存
参考资料:
https://www.cnblogs.com/slly/p/6732749.html 浏览器缓存机制详解
https://www.cnblogs.com/echolun/p/9419517.html http缓存详解,http缓存推荐方案
https://blog.youkuaiyun.com/guduyibeizi/article/details/81814577 HTTP缓存机制详解
https://www.cnblogs.com/chenqf/p/6386163.html 彻底弄懂HTTP缓存机制及原理
https://www.cnblogs.com/fmyao/p/12725628.html 浏览器缓存类型
https://blog.youkuaiyun.com/handsomexiaominge/article/details/80556769 浏览器缓存机制分析及前端缓存清理