缓存是一种保存资源副本并在下次请求时直接使用该副本的技术。(MDN)javascript
这里的web浏览器缓存主要指http缓存。css
内存缓存具备两个特色,分别是快速读取和时效性:快速读取:内存缓存会将编译解析后的文件,直接存入该进程的内存中,占据该进程必定的内存资源,以方便下次运行使用时的快速读取。时效性:一旦该进程关闭,则该进程的内存则会清空。html
硬盘缓存则是直接将缓存写入硬盘文件中,读取缓存须要对该缓存存放的硬盘文件进行I/O操做,而后从新解析该缓存内容,读取复杂,速度比内存缓存慢。java
以浏览器中显示的说明为列:web
浏览器请求一个资源时,会按照优先级(Service Worker -> Memory Cache -> Disk Cache -> Push Cache)依次查找缓存,若是命中则使用缓存,不然发起请求。算法
以未开通Service Worker的服务访问为例:http://baidu.com–> 200 –> 关闭页面的标签页 –> 从新打开http://baidu.com –> 200(from disk cache) –> 刷新 –> 200(from memory cache)。编程
网关缓存、CDN、反向代理缓存、负载均衡器等部署在服务器上的缓存浏览器
以腾讯 CDN 为例:请求头中 X-Cache-Lookup:Hit From MemCache 表示命中 CDN 节点的内存;X-Cache-Lookup:Hit From Disktank 表示命中 CDN 节点的磁盘;X-Cache-Lookup:Hit From Upstream 表示没有命中 CDN。缓存
关键步骤以下:服务器
制强制缓存的字段分别是请求头中的Expires和,其中Cache-Control优先级比Expires高。
Expires是HTTP/1.0控制网页缓存的响应头字段,其值为服务器返回该请求结果缓存的到期时间,即再次发起该请求时,若是客户端的时间小于Expires的值时,直接使用缓存结果。
Expires是HTTP/1.0的字段,可是如今浏览器默认使用的是HTTP/1.1,那么在HTTP/1.1中网页缓存仍是否由Expires控制?
到了HTTP/1.1,Expire已经被Cache-Control替代,缘由在于Expires控制缓存的原理是使用客户端的时间与服务端返回的时间作对比,那么若是客户端与服务端的时间由于某些缘由(例如时区不一样;客户端和服务端有一方的时间不许确)发生偏差,那么强制缓存则会直接失效,这样的话强制缓存的存在则毫无心义。
HTTP/1.1定义的 Cache-Control 头用来区分对缓存机制的支持状况, 请求头和响应头都支持这个属性。经过它提供的不一样的值来定义缓存策略。
Pragma 是HTTP/1.0标准中定义的一个header属性,请求中包含Pragma的效果跟在头信息中定义Cache-Control: no-cache相同,可是HTTP的响应头没有明肯定义这个属性,因此它不能拿来彻底替代HTTP/1.1中定义的Cache-control头。一般定义Pragma以向后兼容基于HTTP/1.0的客户端。
协商缓存的标识也是在响应报文的HTTP头中和请求结果一块儿返回给浏览器的,控制协商缓存的字段分别有:Last-Modified / If-Modified-Since和Etag / If-None-Match,其中Etag / If-None-Match的优先级比Last-Modified / If-Modified-Since高。
属于 http 1.0。当带着 If-Modified-Since 头访问服务器请求资源时,服务器会检查 Last-Modified,若是 Last-Modified 的时间早于或等于 If-Modified-Since 则会返回一个不带主体的 304 响应,不然将从新返回资源。
Last-Modified只能精确到一秒,能够做为一种弱校验器。
属于 http 1.1。ETag 是一个响应首部字段,强校验器,它是根据实体内容生成的一段 hash 字符串,标识资源的状态,由服务端产生。If-None-Match 是一个条件式的请求首部。若是请求资源时在请求首部加上这个字段,值为以前服务器端返回的资源上的 ETag,则当且仅当服务器上没有任何资源的 ETag 属性值与这个首部中列出的时候,服务器才会返回带有所请求资源实体的 200 响应,不然服务器会返回不带实体的 304 响应。
Last-Modified 标注的最后修改只能精确到秒级,若是某些文件在 1 秒钟之内,被修改屡次的话,它将不能准确标注文件的新鲜度;
某些文件也许会周期性的更改,可是他的内容并不改变(仅仅改变的修改时间),但 Last-Modified 却改变了,致使文件无法使用缓存;
有可能存在服务器没有准确获取文件修改时间,或者与代理服务器时间不一致等情形。
ETag 优先级比 Last-Modified 高,同时存在时会以 ETag 为准。
是一个HTTP响应头部信息,它决定了对于将来的一个请求头,应该用一个缓存的回复(response)仍是向源服务器请求一个新的回复。它被服务器用来代表在 content negotiation algorithm(内容协商算法)中选择一个资源表明的时候应该使用哪些头部信息(headers)。它表示某个响应因某个响应头部而不一样。
好比 Vary: Accept 的意思即为,响应因请求资源格式头部而不一样,那么经过相同 URI 访问的资源就能够根据这个头上知道其内容格式不一样。
同一个 URL 能够提供多份不一样的文档,这就要求服务端和客户端之间有一个选择最合适版本的机制,这叫作内容协商。服务端根据客户端发送的请求头中某些字段自动发送最合适的版本。能够用于这个机制的请求头字段又分两种:内容协商专用字段(Accept 字段)、其余字段。
例如:Accept-Encoding 属于内容协商专用字段,服务端只须要在响应头中增长 Content-Encoding 字段,用来指明内容压缩格式;或者不输出 Content-Encoding 代表内容未通过压缩。缓存服务器,针对不一样的 Content-Encoding 缓存不一样内容,再根据具体请求中的 Accept-Encoding 字段返回最合适的版本。增长 Vary: Accept-Encoding 响应头,明确告知缓存服务器按照 Accept-Encoding 字段的内容,分别缓存不一样的版本;
F5的做用和直接在URI输入栏中输入而后回车是不同的,F5会让浏览器不管如何都发一个HTTP Request给Server,即便先前的响应中有Expires头部。因此,当我在 网页中按F5的时候,浏览器会发送一个HTTP Request给Server,可是包含这样的Headers:
Cache-Control: max-age=0 If-Modified-Since: Fri, 15 Jul 2016 04:11:51 GMT
其中Cache-Control是Chrome强制加上的,而If-Modified-Since是由于获取该资源的时候包含了Last-Modified头部,浏览器会使用If-Modified-Since头部信息从新发送该时间以确认资源是否须要从新发送。 实际上Server没有修改这个index.css文件,因此返回了一个304(Not Modified),这样的响应信息很小,所消耗的route-trip很少,网页很快就刷新了。
上面的例子中没有ETag,若是Response中包含ETag,F5引起的Http Request中也是会包含If-None-Match的。
以上描述的客户端浏览器缓存是指存储位置在客户端浏览器, 可是对客户端浏览器缓存的实际设置工做是在服务器上的资源中完成的. 虽然上面介绍了有关于客户端浏览器缓存的属性, 可是实际上对这些属性的设置工做都须要在服务器的资源中作设置. 一般有两种操做手段对浏览器缓存进行设置, 一个是经过指令声明来设置, 另一个是经过编程方式来设置.
例子1
配置指令expires,能够控制 HTTP 响应中的Expires和Cache-Controle的值,默认是 off
location ~ .*.(js|css)?$ { expires 1y; }
例2:
对全部后缀为.html 的请求,返回头 cache-control 使用 no-cache 指令
location ~ .*\.(html)$ { try_files $uri $uri/ =404; root /data/web/default; add_header Cache-Control no-cache; }
例3:
etag设置
http { etag off;
例4
配置last-modified(默认开启)
这里再也不详细描述,不一样语言做出的server服务可查看相关模块说明
以koa实现为例:
//koastart var koa = require('koa'); var app = new koa(); // response app.use(function *(){ this.body = 'Hello World'; var etag = this.get('ETag'); console.log("etag:"+etag); var date = new Date; var hashStr = this.body; var hash = require("crypto").createHash('sha1').update(hashStr).digest('base64'); this.set({ 'Cache-Control':'max-age=120', 'Etag': hash, 'Last-Modified': new Date }); }); app.listen(3000);
MDN-http缓存:https://developer.mozilla.org... ;
HTTP缓存控制:https://imweb.io/topic/5795dc... ;
https://web.dev/http-cache/ ;
https://mp.weixin.qq.com/s/d2... ;
https://www.jiqizhixin.com/ar... ;