HTTP的缓存机制的那些事儿

1.HTTP缓存概述

缓存的重要性不言而喻,通过网络请求资源缓慢并且降低了客户端的用户体验,增添了服务端的负担。很多短期之内不会经常发生变化的资源文件没必要每次访问都想服务端进行数据请求,而缓存策略的使用就是为了改善客户端的呈现时间,降低服务端的负担。
对于HTTP的缓存机制来说,策略体现在HTTP的头部信息的字段上,而这些策略根据是否需要重新向服务器端发起请求可以分为强缓存协商缓存两大类。

2. 强缓存

强缓存紧密联系着一个缓存时间期限,当浏览器请求资源的时候会查看缓存中的资源是否存在并且确定该缓存的资源是否过了“保质期”,若没有超过保质期则将取得缓存中的资源进行下一步处理。
HTTP的缓存机制的那些事儿

与强缓存相关的HTTP header 的字段有两个 Expires以及Cache-Control

2. Expires

expires 字段规定了缓存的资源的过期时间,在此时间之前,缓存中的资源都是有效的,该字段的 value 是一个格林威治时间格式(GMT)的时间,即世界标准时间,js 通过 new Date().toUTCString()可得到,形如 Tue, 27 Feb 2018 06:37:48 GMT。他的缺点很明显,时间期限是服务器生成,存在着客户端和服务器的时间误差,固定时间,HTTP 1.0时的规范。相比较接下来介绍的cache-control优先级较低。

3. cache-control

该字段的值(默认为private):
HTTP的缓存机制的那些事儿

其中最常用的值max-age单位为秒,对比expires体现着一个相对时间,即多少秒后这个强缓存机制下的缓存资源失效。
publicprivate区别在于是否有中间商赚差价(是否允许CDN代理服务器缓存)
需要注意的一点是该字段值定义为no-cache并不是说,不准使用缓存,而是需要走接下来的优先级相对较低的另一类–协商缓存。真正决定不用缓存内的资源是将该值定义为no-store。

3. 协商缓存

协商缓存是通过客户端和服务端进行HTTP通信时,所在响应头和请求头中互相表达“暧昧”的,相互通气,互送缓存标识。
协商缓存无论如何都会和服务器交互,比较强缓存稍微要复杂一点,但是二者是相辅相成并且可以共同存在的,强缓存优先级较高,意味着请求一个资源时会先比较强缓存的字段,如果命中则不会再执行接下来的协商缓存的过程。

1. Last-Modified 和 If-Modified-Since

第一次请求某一个资源时,由于一定不会走缓存,所以服务器端会在资源的响应头中加上一个形如Last-Modified:Mon, 26 Feb 2018 06:37:41 GMT的字段告诉客户端浏览器,这个资源上次最后修改的时间;刷新页面再次请求,这时候的协商缓存会在请求头中加上一个形如If-Modified-Since:Mon, 26 Feb 2018 06:37:41 GMT,字面翻译就是,是否在上个“暧昧”时间后修改了,值毫无疑问是服务端上一次响应给他的时间,让服务器去判断是否在此时间之后资源内容发生了变化。

整个过程也很简单,最后的结果也很简短。如果服务端发现改变了资源,就伴着200的 statuscode 和新鲜的资源给到客户端,若是没有修改,304 Not Modified让客户端从缓存中取。

2. Etag 和 If-None-Match

同样,第一次客户端请求一个资源文件时,服务端随资源在响应头部中甩来一个字段 Etag ,形如ETag:W/"1823823287"该字段的值是该资源在服务器端的唯一标识,生成的Etag值的策略有服务端决定,总之是资源的一个唯一的标识。资源发生变化则该值也发生变化。下一次客户端请求同一个资源的时候,在请求头将这次得到的值放在请求头中一个叫 If-None-Match 的字段中甩给服务端。

如果使用前端打包工具,可以在打包文件时候在给文件添加版本号或者hash值,同样可以区分资源是否过期。

整个过程也很简单,最后的结果也很简短。如果服务端发现改变了资源,就伴着200的 statuscode 和新鲜的资源给到客户端,若是没有修改,304 Not Modified让客户端从缓存中取。
上述两个方式中,Etag 和 If-None-Match的优先级要高于Last-Modified 和 If-Modified-Since,进而会衍生出一个思考,二者相比功能相同,但是表达形式决定了 Etag 解决了 Last-Modified 存在的一些问题,比如Last-Modified 是比较时间,精确到秒,若是毫秒级的改变则没法兼顾,存在着周期性更改的资源,然而有可能资源本身的内容并没有改变,那如果重新请求响应意义并不是那么的大。所以不难理解Etag具有高优先级有他的合理之处。

4. http缓存过程图

首先看有没有缓存,没有的话直接请求服务器,这时候没出意外的话,正常地返回应该是200
有缓存然后看是否过期,没过期的话就用缓存的资源了这时候不会发器请求
如果过期了再向服务器发起请求看资源是否有修改,如果没修改则返回304,如果修改了则返回200连同最新的资源一起返回,更新浏览器缓存副本。
HTTP的缓存机制的那些事儿

https://segmentfault.com/a/1190000016152384
http://www.alloyteam.com/2016/03/discussion-on-web-caching/#prettyPhoto