前言:“学习提升往往是打破思维壁垒的过程”,缓存策略是一个封闭的既成事实?还是只是一个约定规则?客户度的事被浏览器做了多少?服务端也是如此么? 还是只是被框架阻拦了思维,只是框架替你做了,如果进入底层,一些要自己写,那这些只是规则?是否也能被改写?
(阅读文章前,先理解观点1,带着观点看文章)
【观点1】:缓存规则是一个客观事实么?不,对于服务端而言,它可以只是一个主观设置的规则。
一、缓存原理
=======================
1、通过地址栏的链接访问不会使用缓存(也就是入口文件必定访问服务器),入口文件中引入的文件资源才会被缓存。
2、缓存是浏览器和服务器端的游戏,判断条件只有【两点】:
1、【当前缓存是否过期?】 不管过没过期(过期了继续使用),如文件没有改变,返回304,启用缓存;
2、【服务器中的文件是否有改动?】 即便没过期,但是改动了,也会返回200,并送上新文件与新修改日期
二、如何实现缓存
========================
1、【缓存期限】:请求头中携带期限字段,有两种字段方式(以前还有一种pragma,优先级最高,不过慢慢抛弃了)
【Expires】:直接标明过期时间,绝对时间;
【Cache-Control(max-age)】:max-age存放是一个时间段,相对时间。优先级高,并且排挤Expires,Cache-Control配置了max-age时Expires失效。
2、【文件变动】: 判断文件变动有两种标识方式 ETag 、Last-modified
【ETag】:响应头返回ETag标识(hash值),下次请求头携带If-None-Match,服务端对比两值,相等则返回304,不等则返回200,新资源新ETag。
(也可以用If-Match,区别是如果不一致,返回状态码412)
【Last-modified】:响应头返回最后修改时间,下次请求头携带 If-Modified-Since,服务端对比两值,相等则返回304,否则返回200并带上新的Last-modified。
(也可以用If-Unmodified-Since,区别是如果时间不一致,返回状态码412)
三、如何通过 Cache-Control 支配缓存(Cache-Control 在请求头与响应头中都有使用)
===============================================================
使用示例:Cache-Control: must-revalidate, max-age=60
请求头与响应头都可使用
1、no-cache:还是有缓存的,只不过客户端(代理服务器)每次都要先向服务器发起请求,验证过了再决定是否使用缓存
2、no-store:完全不使用缓存,每次都向服务器获取新资源
3、max-age=60:客户端向服务器索要有效期60秒的资源 服务器告知客户端该资源60秒内为新鲜,不许再向服务器发起请求(跟第一次请求时间对比)。max-age<=0,立即过期的响应(记为陈旧状态),向server发起请求,资源是否修改 ,返回200 ,或304。
只用在响应头中的使用
1、public:任何情况都要缓存该资源(如果定义了max-age,可以不用再定义public,意义是一样的),可以和no-cache结合使用
2、private[=“field-name”]:返回文件中全部或部分(field-name为指定的部分内容)仅开放给某些用户(服务器指定的share-user,如代理服务器)做缓存使用,其他用户不能缓存
3、must-revalidate:资源还在max-age的缓存期内则直接使用缓存,过期后必须到服务器验证
四、强缓存与协商缓存
===============================================================================
chrome、safari中状态码为200的时候也是有可能读缓存的,而且还是强缓存,而火狐没有这样的策略,还是走协商缓存,返回304,这也是chrome更快的原因。
1、200 ok 从服务器下载资源
2、200 ok(from memory cach) 从内存获取缓存,一般为脚本、字体、图片,关闭浏览器会被释放
3、200 ok(from disk cache) 从磁盘获取缓存,一般为css,关闭浏览器不会消失
样式表一般在磁盘中,不会缓存到内存中去,因为css样式加载一次即可渲染出网页。但是脚本却可能随时会执行,如果脚本在磁盘当中,在执行该脚本需要从磁盘中取到内存当中来,这样的IO开销是比较大的,有可能会导致浏览器失去响应。
注:200 ok 中标注的是文件真实大小,而304 Not Modified 中标注的有可能(分浏览器)是通信报文的大小,不是文件的大小。
下面对比同一个文件app.js,chrome 和火狐对比
======================
1、chrome 中再General中标注200(from memory cache)状态,响应头中状态还是304
=====================
2、火狐:看缓存是否命中很方便
————————
下表是在不同浏览器中,cache-control与etag作用的罗列
|
Chrome |
Safari |
Firefox |
QQ浏览器 |
max-age=0 |
200 |
200 |
200 |
200 |
max-age=60 |
200 (from memory cache) |
200 (来源内存缓存) |
200 |
200 |
max-age=60 ETag |
200 (from memory cache) |
200 (来源内存缓存) |
304 |
304 |
max-age=60,no-cache ETag |
304 |
304 |
304 |
304 |
总结:
1、Chrome,Safari浏览器中,有200 (读取内存缓存)策略,只要响应头出现 catch-control:max-age=60,在60秒内就一定强读缓存。如果想要走304验证缓存,便加上no-cache。
2、在chrome中,'max-age=5’失效后,再次请求可能不是200,而是304,因为再请求已经有了If-None-Match、If-Modified-Since标记,这时候就看服务器的策略了,如果服务器端验证了文件其实并没有修改,允许重用已过期缓存,则返回304,并在响应头中携带新的过期时间。显示的过程是:第一次200,5秒内200(from memory cache),5秒后304,再接来下5秒继续200(from memory cache)
QA:
1、带if标记(如If-None-Match、If-Modified-Since),浏览器就一定有缓存么,万一浏览器没有缓存怎么办
A:当浏览器在请求头加上if标识,则代表已经有缓存
1、must-revalidate, max-age=5中,must-revalidate意义何在,没有它,60秒到期后,也会去服务端请求啊
A:这是针对缓存服务器的。缓存服务器,可以通过配置,提供一些陈旧的对象,以提高性能。如果原始服务器希望缓存能遵守过期信息,可以在相应头部添加cache-control: must-revalidate,告诉缓存,过期后,在没有跟服务器校验的情况下,不能提供这个对象的旧版本,如果服务器不可用,那么缓存服务器必须返回504错误(网关超时错误:网关或代理服务器,没有及时从上游服务器收到请求)
2、200不使用缓存么?304就是调用缓存么?怎么确定命中缓存?代理服务器的缓存呢?
A:200不一定就是获取数据,有可能是读取内存磁盘缓存,304代表转向
请求头部有max-stale,表示可接受过期的响应
Html5应用程序缓存(Cache manifest)