浏览器缓存的都是派生资源。css
Webkit资源分红两类,chrome
一类是主资源,好比HTML页面,或者下载项,windows
一类是派生资源,好比HTML页面中内嵌的图片或者脚本、样式表连接,浏览器
资源加载失败的处理,主资源下载失败会有报错提示,而派生资源如图片下载失败,每每只显示一个占位符。缓存
WebKit派生资源包含的类型主要以下:服务器
Javascript脚本(CachedScript);网络
CSS样式文本(CachedCSSStyleSheet);字体
图片(CachedImage);url
字体(CachedFont);spa
XSL样式表(CachedXSLStyleSheet);
能够说除了主资源剩下的网络资源都是派生资源。
客户端缓存就是指用户设备中的本地资源。
不一样操做系统不一样浏览器缓存文件的地址也不尽相同。
本人用的mac,实在是没搞懂这个地址在哪里。
就以别人的旧图,windows chrome为例来查看下浏览器缓存文件的地址。
1)首先在chrome中输入:chrome://chrome-urls/,看到一堆列表,里面隐藏了许多浏览器的奥秘,有兴趣的能够本身深扒。
2)找到 chrome://cache(固然也能够直接输入这个地址)
打开一个css缓存文件连接,以下图pic-1
在图中能够看到,客户端保留了一个服务器端的response header。
header中有不少的字段,举例说几个。
Date字段表示这次缓存时服务器的时间。
expires字段表示过时时间,Thu, 28 Sep 2017 06:38:37GMT。
Cache-control: max-age 能够控制缓存时间。
Last-Modified和ETag也会出如今里面。
Cache-Control 是 Http1.1 中的标准,能够当作是 expires 的补充,使用的是相对时间的概念。
也就是说,强缓存和协商缓存用到的字段都在里面。
也能够得出结论,浏览器断定是否有缓存,就是浏览器去判断本地缓存目录下是否有该对应的请求
下面,咱们根据浏览器请求流程来分析浏览器静态资源的缓存机制
1️⃣浏览器请求,判断无缓存时(如何判断缓存上文已讲明再也不赘述):
在这个阶段(通常为第一次请求),客户端判断本地无缓存时,直接向服务器请求资源。
服务器通常会将Cache-control、expires 、last-modified、date、etag 等字段在response header 中返回,便于下次缓存。固然具体的场景,也是看服务器的约定规则设定。
2️⃣浏览器请求,判断有缓存时:
当客户端判断本地有缓存时,紧接着要判断当前缓存资源是否过时。
3️⃣判断当前缓存是否过时,就是判断是否命中强缓存的过程
强缓存
用户发送的请求,直接从客户端缓存中获取,不发送请求到服务器,不与服务器发生交互行为。
协商缓存
用户发送的请求,发送到服务器后,由服务器断定是否从缓存中获取资源。
二者共同点:客户端得到的数据最后都是从客户端缓存中得到。
在介绍如何判断缓存是否过时前,先简单介绍下强缓存相关的header字段
expires:这是http1.0时的规范;它的值为一个绝对时间的GMT格式的时间字符串,如Mon, 10 Jun 2015 21:31:12 GMT,若是发送请求的时间在expires以前,那么本地缓存始终有效,不然就会发送请求到服务器来获取资源
cache-control:max-age=number:这是http1.1时出现的header信息,主要是利用该字段的max-age值来进行判断
Cache-Control的属性设置:
1)max-age: 设置缓存的最大的有效时间,单位为秒(s)。max-age会覆盖掉Expires
2) s-maxage: 只用于共享缓存,好比CDN缓存(s -> share)。
与max-age 的区别是:max-age用于普通缓存,而s-maxage用于代理缓存。若是存在s-maxage,则会覆盖max-age 和 Expires.
3) public:响应会被缓存,而且在多用户间共享。默认是public。
4) private: 响应只做为私有的缓存,不能在用户间共享。若是要求HTTP认证,响应会自动设置为private。
5)no-cache: 指定不缓存响应,代表资源不进行缓存。
可是设置了no-cache以后并不表明浏览器不缓存,而是须要使用缓存协商,在缓存前要向服务器确认资源是否被更改。所以有的时候只设置no-cache防止缓存仍是不够保险,还能够加上private指令,将过时时间设为过去的时间。
6)no-store: 绝对禁止缓存。
7)must-revalidate: 若是页面过时,则去服务器进行获取。
以下图,浏览器在请求某一资源时,会先获取该资源缓存的header信息,判断是否命中强缓存(cache-control和expires信息)。
1)查看是否有cache-control 的max-age / s-maxage , 若是有,则用服务器时间date值 + max-age/s-maxage 的秒数计算出新的过时时间,将当前时间与过时时间进行比较,判断是否过时
2)查看是否有cache-control 的max-age / s-maxage,若是没有,则用expires 做为过时时间比较
根据所讲的判断方式,按照上面的流程图,若是缓存没有过时,则返回的response状态为200 from memory cache或者200 from disk cache,从而直接从缓存获取资源,包括缓存header信息,不发送请求到服务器。
200 from memory cache
不访问服务器,直接读缓存,从内存中读取缓存。此时的数据时缓存到内存中的,当kill进程后,也就是浏览器关闭之后,数据将不存在。可是这种方式只能缓存派生资源
200 from disk cache 不访问服务器,直接读缓存,从磁盘中读取缓存,当kill进程时,数据仍是存在。这种方式也只能缓存派生资源
通常浏览图片,以下流程:
访问-> 200 -> 退出浏览器
再进来-> 200(from disk cache) -> 刷新 -> 200(from memory cache)
若是缓存过时了,即没有命中强缓存,则判断是否命中协商缓存。
Last-modified: 代表请求的资源上次的修改时间。
If-Modified-Since:客户端保留的资源上次的修改时间。
Etag:资源的内容标识。(不惟一,一般为文件的md5或者一段hash值,只要保证写入和验证时的方法一致便可)
If-None-Match:客户端保留的资源内容标识。
协商缓存都是由服务器来肯定缓存资源是否可用的,因此客户端与服务器端要经过某种标识来进行通讯,从而让服务器判断请求资源是否能够缓存访问,这主要涉及到下面两组header字段,这两组搭档都是成对出现的,即第一次请求的响应头带上某个字段(Last-Modified或者Etag),则后续请求则会带上对应的请求字段(If-Modified-Since或者If-None-Match),若响应头没有Last-Modified或者Etag字段,则请求头也不会有对应的字段。
1)比对Last-Modified/If-Modified-Since:
浏览器会发送请求到服务器,请求会携带第一次或者上一次请求返回的有关缓存的header字段信息(Last-Modified/If-Modified-Since),服务器再次收到资源请求时,根据浏览器传过来If-Modified-Since和资源在服务器上的最后修改时间判断资源是否有变化。
若是没有变化,则返回304 Not Modified,可是不会返回资源内容。response header中不会再添加Last-Modified的header,由于既然资源没有变化,那么Last-Modified也就不会改变。
304 Not Modified 访问服务器,发现数据没有更新,服务器返回此状态码。而后从缓存中读取数据。
若是有变化,就正常返回资源内容。浏览器直接从服务器加载资源时,Last-Modified的Header在从新加载的时候会被更新,下次请求时,If-Modified-Since会启用上次返回的Last-Modified值
2)比对Etag/If-None-Match:
这两个值是由服务器生成的每一个资源的惟一标识字符串,只要资源有变化就这个值就会改变,其判断过程与Last-Modified/If-Modified-Since相似。
与Last-Modified不同的是,当服务器返回304 Not Modified的响应时,因为ETag从新生成过,response header中还会把这个ETag返回,即便这个ETag跟以前的没有变化。
HTTP1.1中Etag的出现主要是为了解决几个Last-Modified比较难解决的问题:
这时,利用Etag可以更加准确的控制缓存,由于Etag是服务器自动生成或者由开发者生成的对应资源在服务器端的惟
一标识符。
Last-Modified与ETag是能够一块儿使用的,服务器会优先验证ETag,一致的状况下,才会继续比对Last-Modified,最后才决定是否返回304。
4️⃣若是没有命中协商缓存,则直接从服务器获取数据,返回200
上面的搞懂了,下面就是个小总结
三级缓存原理
1️⃣先去内存看,若是有,直接加载
2️⃣若是内存没有,择取硬盘获取,若是有直接加载
3️⃣若是硬盘也没有,那么就进行网络请求
4️⃣加载到的资源缓存到硬盘和内存
用户行为
附上一张,用户行为影响浏览器的缓存行为。