HTTP缓存机制及原理

1、前言

       上周阿里的面试官问了个面试题 “ 能不能说下 304 的过程,以及影响缓存的头部属性有哪些?”OMG.......由于以前只是大概了解 304 状态码是表示缓存,且由于平时项目开发过程当中也没有在缓存这块踩过坑,因此这一块也没有去作特别深刻的研究。因此当被问这个问题时,有被当头一棒的感受,也好好反思了下,本身校招以软件开发工程师的职位进入公司,以前没有想过要从事前端开发,因此前端基础几乎能够忽略不计。工做一年多来,为在工做上表现突出,在工做上投入大量的精力,干到晚上10点是常规操做,周末至少加班1天;而且空余时间,常常看前端相关书籍弥补基础,如《JavaScript 高级程序设计》、《CSS 权威指南》、《Sass 实践》、《JavaScript 高性能编程》....《Webpack 实践》、《深刻浅出 node.js》等不下10本书;在广度上涉及的仍是不少的,可是存在问题:从事前端时间不长,前端知识杂而多,若是没有专门准备,若是忽然问你一个知识点,你虽然大概知道这是啥,可是让你讲的话,你很难有条理的讲清楚。
       So,下一阶段的首要任务:“打好打牢前端基础,深刻了解所用的技术栈原理”。废话少说,学问学问,不懂就弄清楚!如下“ 理论知识 + 实践操做”来完全弄懂 HTTP 缓存机制及原理!

2、缓存规则及解析

       为方便你们理解,我假设览器存在一个缓存数据库,用于存储缓存信息。在客户端第一次请求数据时,此时缓存数据库中没有对应的缓存数据,须要请求服务器,服务器返回后,将数据存储至缓存数据库中。以下流程图所示:
       根据是否须要从新向服务器发起请求来分类,将HTTP缓存规则分为两大类( 强制缓存对比缓存)在详细介绍这两种规则以前,先经过时序图的方式,让你们对这两种规则有个简单了解。
(1)已存在缓存数据时,仅基于 强制缓存,请求数据的流程以下所示:


(2)已存在缓存数据时,仅基于 对比缓存,请求数据的流程以下所示:


       咱们能够看到两类缓存规则的不一样, 强制缓存若是生效,不须要再和服务器发生交互,而 对比缓存不论是否生效,都须要与服务端发生交互。
       两类缓存规则能够同时存在, 强制缓存优先级高于 对比缓存,也就是说,当执行 强制缓存的规则时,若是缓存生效,直接使用缓存,再也不执行 对比缓存规则。

3、缓存经常使用字段

一、http1.0时期的缓存方案


注意: 前端

(1)若是使用了Pragma: 'no-cache'的话,再设置Expires或者Cache-Control,就没有用了,说明Pragma的权值比后二者高。node

 (2)若是设置了Expires以后,客户端在须要请求数据的时候,首先会对比当前系统时间和这个Expires时间,若是没有超过Expires时间,则直接读取本地磁盘中的缓存数据,不发送请求。
ios

二、http1.1 时期的缓存方案

2.一、Cache-Control 字段 面试

2.1.一、Cache-Control 做为请求头字段
数据库


(1)Cache-Control: no-cache 编程

使用no-cache指令的目的是为了防止从缓存中返回过时的资源。 客户端发送的请求中若是包含 no-cache 指令,则表示客户端将不会接收缓存的资源。每次请求都是从服务器获取资源,返回304。  axios

(2)Cache-Control: no-store 浏览器

使用no-store 指令表示请求的资源不会被缓存,下次任何其它请求获取该资源,仍是会从服务器获取,返回 200,即资源自己。
缓存

2.1.二、Cache-Control 做为响应头字段
服务器


Cache-Control: public 

当指定使用 public 指令时,则明确代表其余用户也可利用缓存。

 Cache-Control: private

当指定 private 指令后,响应只以特定的用户做为对象,这与 public 指令的行为相反。 缓存服务器会对该特定用户提供资源缓存的服务,对于其余用户发送 过来的请求,代理服务器则不会返回缓存。

 Cache-Control: no-cache 

若是服务器返回的响应中包含 no-cache 指令,每次客户端请求,必需先向服务器确认其有效性,若是资源没有更改,则返回304. 

Cache-Control: no-store 

不对响应的资源进行缓存,即用户下次请求仍是返回 200,返回资源自己。 

Cache-Control: max-age=604800(单位:秒) 

资源缓存在本地浏览器的时间,若是超过该时间,则从新向服务器获取。

2.二、请求头部字段 & 响应头部字段

2.2.一、请求头部字段


2.2.二、响应头部字段


注意:

 (1)If-None-Match的优先级比If-Modified-Since高,因此二者同时存在时,听从前者。

4、实验验证

一、实验1 — 请求的资源没修改,验证2种缓存出现的情形
服务端使用 node.js , 客户端使用 axios 进行请求:
1.一、请求头部 / 响应头部 设置
(1)服务端响应头部设置:
     res.setHeader('Cache-Control', 'public, max-age=10');
(2)客户端请求头部使用默认设置

1.二、实验步骤
(1)请求 3 次,第一次请求请求资源;第二次在10秒内再次请求该资源,第三次在 10 秒后再次请求该资源(实验过程当中,服务端的资源没有进行改变)

1.三、实验结果
      3 次请求的 HTTP 信息以下图所示,从图中的信息能够得出,第一次请求该资源是从服务器获取;第二次(10 秒内)请求该资源是直接从浏览器缓存中获取该资源(没有向服务器确认);第三次(10 秒后)请求该资源时,由于资源缓存时间(10 秒)过时,因此向服务器获取资源,服务器判断该资源与本地缓存的资源没有作更改,因此返回 304,让客户端直接从浏览器缓存中获取该资源;如下,根据 HTTP 头部信息详细介绍三个操做的交互过程。


1.3.一、第一次请求资源
第一次请求资源的请求头部和响应头部的截图以下所示,由于第一次请求该资源,本地并无缓存,因此直接从服务器获取该资源;咱们从截图能够看到,服务器返回改资源的响应头部中包含3个属性与资源缓存相关:
(1) cache-control: public, max-age=10
缓存规则的设置,咱们这个示例中,设置缓存规则为 public, 而且设置缓存过时时间为10秒;
(2) etag: W/"95f15b-16994d7ebf6"
资源的惟一标识符,客户端下次访问该资源时,会在请求头中携带 etag 去向服务器确认,该资源是否被修改;
(3 )last-modified: Tue, 19 Mar 2019 07:26:12 GMT
资源最后一次修改时间,客户端下次访问该资源时,会在请求头中携带该信息去向服务器进行匹配,该资源是否被修改;


1.3.二、第二次请求资源(10秒内,即在缓存时间失效前)
       第二次请求资源的请求头部和响应头部的截图以下所示,由于第二次请求该资源,该资源本地缓存还没失效,因此就直接从浏览器缓存中获取该资源。


1.3.三、第三次请求资源(10秒后,即在缓存时间失效后)
       第三次请求资源的请求头部和响应头部的截图以下所示,由于第三次请求该资源,该资源本地缓存已经失效,因此在请求头部中加入 If-Modified-Since If-None-Match 属性,来向服务器进行确认该资源是否有被更改。



二、实验2 — 请求的资源进行修改,验证2种缓存出现的情形
服务端使用 node.js , 客户端使用 axios 进行请求:
2.一、请求头部 / 响应头部 设置
(1)服务端响应头部设置:
     res.setHeader('Cache-Control', 'public, max-age=20');
(2)客户端请求头部使用默认设置

2.二、实验步骤
(1)请求 3 次,第一次请求资源;而后在服务器对请求的资源进行修改,第二次在 20 秒内再次请求该资源,第三次在 20 秒后再次请求该资源

2.三、实验结果
       3 次请求的 HTTP 信息以下图所示,从图中的信息能够得出,第一次请求该资源是从服务器获取;第二次(20 秒内)请求该资源是直接从浏览器缓存中获取该资源(没有向服务器确认);第三次(20 秒后)请求该资源时,由于资源缓存时间(20 秒)过时,因此向服务器获取资源,服务器判断该资源与本地缓存的资源不一样,因此从新返回该资源;如下,根据 HTTP 头部信息详细介绍三个操做的交互过程。


2.3.一、第一次请求资源
       第一次请求资源的请求头部和响应头部的截图以下所示,具体详细信息与 1.3.1 小节相同,在此不一样重复介绍。


2.3.二、第二次请求资源(20 秒内,即在缓存时间失效前)
      第二次请求资源的请求头部和响应头部的截图以下所示,(注意:即便此时服务器上的资源已经更改,可是因为缓存在浏览器中的资源没有过时,因此仍是从缓存中返回旧资源)。


2.3.三、第三次请求资源(20 秒后,即在缓存时间失效后)
       第三次请求资源的请求头部和响应头部的截图以下所示,由于第三次请求该资源,该资源本地缓存已经失效,因此在请求头部中加入 If-Modified-Since If-None-Match 属性,来向服务器进行确认该资源是否有被更改,从下图中能够看到,响应头部的属性 etag 与 请求头部的属性 If-None-Match 不一样,响应头部的属性 If-Modified-Since 与 请求头部的属性 last-modified 不一样;因此服务器返回该资源的最新资源。


5、总结

一、对于强制缓存,服务器通知浏览器一个缓存时间,在缓存时间内,下次请求,直接用缓存,不在时间内,执行比较缓存策略。
二、对于比较缓存,将缓存信息中的Etag和Last-Modified经过请求发送给服务器,由服务器校验,返回304状态码时,浏览器直接使用缓存。
总结流程图以下所示:




转自深刻理解HTTP缓存机制及原理

相关文章
相关标签/搜索