转载

一文读懂http缓存(超详细)

作者:kim
来自:kimshareclub微信公众号

讲真,现在或许还会有部分人和我一样,对于前端缓存这一块还不是很了解,弄不清楚平时是怎么使用的,不过别急,今天的这篇文章或许会给你指点迷津。前端缓存也是面试过程中常会问到的一个知识点,所以作为前端开发的胖友们可要注意了!首先请允许小编我插入一段前段时间的一个前端面试经历吧!我当时面试的是一家某游戏公司,公司各方面都挺好的,有来自鹅厂的技术大牛,能收到面试邀请也是挺幸运的。下面就直接进入面试环节,当时已经进到了第三轮的面试,具体情况是这样的:

面试官:之前有使用过前端缓存吗?

我:有的,一般都会用到的!
(然后balabala说了一堆使用缓存的好处,其实自己不是很清楚,但不知哪来的自信)

面试官:那你能说说,都是怎么使用的吗?

我:我们之前的用法都是在服务器端配的…
(当时这一问差点就触及到我的知识盲区了,想了一会才想出的这么一个答案…不过确实我们在项目上是这么用的,在springmvc的静态资源处理器中配置的静态资源缓存)

面试官:那http缓存在前端页面上是怎么用的呢?

我:应该可以用js去设置的吧!
(当时的我瞬间懵逼…这部分内容以前真的没怎么留意过,后来就开启了我的瞎逼逼模式)

面试官:那请求头中都有哪些属性是关于http缓存的?

我:这个不太留意,记的不是很清楚了!
(当时头脑一片空白,持续懵逼中。。。)

面试官:那我稍微提示下吧!比如cache-control还有哪些?
(看似很镇定…内心可能早已汹涌澎湃)

我:哦!我知道了,对的,还有个叫no-cache的。。。
(这么一提示,瞬间感觉自己看到了希望,有种豁然开朗的感觉,不过下一秒又陷入了尴尬的局面)

面试官:还有吗?
(心中可能已经有千万只尼玛在奔腾~~~)

我:其他的就不清楚了。。。
(略显尴尬的回答)

后来面试结果就凉凉了。具体细节就不再详细展开,我怕会触及到我的泪腺555,但也不全是因为这么一个问题导致整个面试垮掉的。后来回去翻了一下关于http缓存的文章,发现这些问题都是最简单不过了,当时说的会,那简直就是狠狠的打脸呀!现在想想就觉得可怕,真的是不知者无畏呀!这是我面试过程中的一个教训,大家可以以我为鉴,如再遇到类似的问题都能应付自如。争取屌丝逆袭,拿高薪,迎娶白富美,尽早走向自己的人生巅峰~~~ 接下来进入今天的主题

前端缓存

前端缓存可分为两大类:http缓存和浏览器缓存。我们今天重点讲的是http缓存,所以关于浏览器缓存大家自行去查阅。下面这张图是前端缓存的一个大致知识点:
image

HTTP缓存

首先是解决困扰人们的老大难问题:

一、什么是HTTP缓存 ?

http缓存指的是: 当客户端向服务器请求资源时,会先抵达浏览器缓存,如果浏览器有“要请求资源”的副本,就可以直接从浏览器缓存中提取而不是从原始服务器中提取这个资源。

常见的http缓存只能缓存get请求响应的资源,对于其他类型的响应则无能为力,所以后续说的请求缓存都是指GET请求。

http缓存都是从第二次请求开始的。第一次请求资源时,服务器返回资源,并在respone header头中回传资源的缓存参数;第二次请求时,浏览器判断这些请求参数,命中强缓存就直接200,否则就把请求参数加到request header头中传给服务器,看是否命中协商缓存,命中则返回304,否则服务器会返回新的资源。

1、http缓存的分类:
根据是否需要重新向服务器发起请求来分类,可分为(强制缓存,协商缓存) 根据是否可以被单个或者多个用户使用来分类,可分为(私有缓存,共享缓存) 强制缓存如果生效,不需要再和服务器发生交互,而协商缓存不管是否生效,都需要与服务端发生交互。下面是强制缓存和协商缓存的一些对比:
image
1.1、强制缓存
强制缓存在缓存数据未失效的情况下(即Cache-Control的max-age没有过期或者Expires的缓存时间没有过期),那么就会直接使用浏览器的缓存数据,不会再向服务器发送任何请求。强制缓存生效时,http状态码为200。这种方式页面的加载速度是最快的,性能也是很好的,但是在这期间,如果服务器端的资源修改了,页面上是拿不到的,因为它不会再向服务器发请求了。这种情况就是我们在开发种经常遇到的,比如你修改了页面上的某个样式,在页面上刷新了但没有生效,因为走的是强缓存,所以Ctrl + F5一顿操作之后就好了。 跟强制缓存相关的header头属性有(Pragma/Cache-Control/Expires)
image
这个Pragma和Cache-Control共存时的优先级问题还有点异议,我在不同的文章里发现:有的说Pragma的优先级更高,有的说Cache-Control高。为了搞清楚这个问题,我决定动手操作一波,首先我用nodejs搭建后台服务器,目的是设置缓存参数,具体代码如下:image
然后再浏览器上访问:http://localhost:8888
第一次访问时都是从后台返回的数据:
image

第二次访问时:
image

image
最终得出结论:
Pragma和Cache-control共存时,Pragma的优先级是比Cache-Control高的。

注意:
在chrome浏览器中返回的200状态会有两种情况:
1、from memory cache
(从内存中获取/一般缓存更新频率较高的js、图片、字体等资源)

2、from disk cache
(从磁盘中获取/一般缓存更新频率较低的js、css等资源)

这两种情况是chrome自身的一种缓存策略,这也是为什么chrome浏览器响应的快的原因。其他浏览返回的是已缓存状态,没有标识是从哪获取的缓存。

chrome浏览器:
image

Firefox浏览器:
image

1.2、协商缓存
当第一次请求时服务器返回的响应头中没有Cache-Control和Expires或者Cache-Control和Expires过期还或者它的属性设置为no-cache时(即不走强缓存),那么浏览器第二次请求时就会与服务器进行协商,与服务器端对比判断资源是否进行了修改更新。如果服务器端的资源没有修改,那么就会返回304状态码,告诉浏览器可以使用缓存中的数据,这样就减少了服务器的数据传输压力。如果数据有更新就会返回200状态码,服务器就会返回更新后的资源并且将缓存信息一起返回。跟协商缓存相关的header头属性有(ETag/If-Not-Match 、Last-Modified/If-Modified-Since)请求头和响应头需要成对出现
image
协商缓存的执行流程是这样的:当浏览器第一次向服务器发送请求时,会在响应头中返回协商缓存的头属性:ETag和Last-Modified,其中ETag返回的是一个hash值,Last-Modified返回的是GMT格式的最后修改时间。然后浏览器在第二次发送请求的时候,会在请求头中带上与ETag对应的If-Not-Match,其值就是响应头中返回的ETag的值,Last-Modified对应的If-Modified-Since。服务器在接收到这两个参数后会做比较,如果返回的是304状态码,则说明请求的资源没有修改,浏览器可以直接在缓存中取数据,否则,服务器会直接返回数据。
image
image

注意:
ETag/If-Not-Match是在HTTP/1.1出现的,主要是解决以下问题:

(1)、Last-Modified标注的最后修改只能精确到秒级,如果某些文件在1秒钟以内,被修改多次的话,它将不能准确标注文件的修改时间

(2)、如果某些文件被修改了,但是内容并没有任何变化,而Last-Modified却改变了,导致文件没法使用缓存

(3)、有可能存在服务器没有准确获取文件修改时间,或者与代理服务器时间不一致等情形

1.3、私有缓存(浏览器级缓存)
私有缓存只能用于单独的用户:Cache-Control: Private

1.4、共享缓存(代理级缓存)
共享缓存可以被多个用户使用: Cache-Control: Public

二、为什么要使用HTTP缓存 ?

根据上面的学习可发现使用缓存的好处主要有以下几点:
1. 减少了冗余的数据传输,节省了网费。
2. 缓解了服务器的压力, 大大提高了网站的性能
3. 加快了客户端加载网页的速度

三、如何使用HTTP缓存 ?

一般需要缓存的资源有html页面和其他静态资源:
1、html页面缓存的设置主要是在标签中嵌入标签,这种方式只对页面有效,对页面上的资源无效
1.1、html页面禁用缓存的设置如下:

<meta http-equiv="pragma" content="no-cache">

// 仅有IE浏览器才识别的标签,不一定会在请求字段加上Pragma,但的确会让当前页面每次都发新请求

<meta http-equiv="cache-control" content="no-cache"> 

// 其他主流浏览器识别的标签

<meta http-equiv="expires" content="0"> 

// 仅有IE浏览器才识别的标签,该方式仅仅作为知会IE缓存时间的标记,你并不能在请求或响应报文中找到Expires字段

1.2、html设置缓存如下:

<meta http-equiv="Cache-Control" content="max-age=7200" />

// 其他主流浏览器识别的标签

<meta http-equiv="Expires" content="Mon, 20  Aug 2018 23:00:00 GMT" /> 

// 仅有IE浏览器才识别的标签

2、静态资源的缓存一般是在web服务器上配置的,常用的web服务器有:nginx、apache。具体的配置这里不做详细介绍,大家自行查阅。

3、不想使用缓存的几种方式:
3.1、Ctrl + F5强制刷新,都会直接向服务器提取数据。
3.2、按F5刷新或浏览器的刷新按钮,默认加上Cache-Control:max-age=0,即会走协商缓存。
3.2、在IE浏览器下不想使用缓存的做法:打开IE,点击工具栏上的工具->Internet选项->常规->浏览历史记录 设置. 选择“从不”,然后保存。最后点击“删除”把Internet临时文件都删掉 (IE缓存的文件就是Internet临时文件)。
3.3、还有就是上面1、2中禁用缓存的做法
3.4、对于其他浏览器也都有清除缓存的办法

四、HTTP缓存的几个注意点

1、强缓存情况下,只要缓存还没过期,就会直接从缓存中取数据,就算服务器端有数据变化,也不会从服务器端获取了,这样就无法获取到修改后的数据。决解的办法有:在修改后的资源加上随机数,确保不会从缓存中取。

例如:
http://www.kimshare.club/kim/common.css?v=22324432
http://www.kimshare.club/kim/common.2312331.css

2、尽量减少304的请求,因为我们知道,协商缓存每次都会与后台服务器进行交互,所以性能上不是很好。从性能上来看尽量多使用强缓存。

3、在Firefox浏览器下,使用Cache-Control: no-cache 是不生效的,其识别的是no-store。这样能达到其他浏览器使用Cache-Control: no-cache的效果。所以为了兼容Firefox浏览器,经常会写成Cache-Control: no-cache,no-store。

4、与缓存相关的几个header属性有:Vary、Date/Age。

Vary:
vary本身是“变化”的意思,而在http报文中更趋于是“vary from”(与。。。不同)的含义,它表示服务端会以什么基准字段来区分、筛选缓存版本。
在服务端有着这么一个地址,如果是IE用户则返回针对IE开发的内容,否则返回另一个主流浏览器版本的内容。
格式:Vary: User-Agent
知会代理服务器需要以 User-Agent 这个请求首部字段来区别缓存版本,防止传递给客户端的缓存不正确。

Date/Age:
响应报文中的 Date 和 Age 字段:区分其收到的资源是否命中了代理服务器的缓存。
Date 理所当然是原服务器发送该资源响应报文的时间(GMT格式),如果你发现 Date 的时间与“当前时间”差别较大,或者连续F5刷新发现 Date 的值都没变化,则说明你当前请求是命中了代理服务器的缓存。
Age 也是响应报文中的首部字段,它表示该文件在代理服务器中存在的时间(秒),如文件被修改或替换,Age会重新由0开始累计。

浏览器缓存

下面说说最常用到的浏览器缓存有:cookie、sessionStorage、localStorage这三者的主要特征如下:
image

课程总结

1、对于强制缓存,服务器通知浏览器一个缓存时间,在缓存时间内,下次请求,直接用缓存,不在时间内,执行协商缓存策略。

2、对于协商缓存,将缓存信息中的Etag和Last-Modified通过请求发送给服务器,由服务器校验,返回304状态码时,浏览器直接使用缓存。

下图是浏览器首次和再次发送http请求的执行流程图:
image
image

这是我在整理http缓存过程中总结的知识点,希望对大家有帮助!由于能力有限,如有纠正之处,欢迎留言指出,谢谢!如果觉得有帮助欢迎关注我的微信公众号,后续还会有更多更精彩的内容~~~

往期热文

* 深入学习ES6【第二章】

* 深入学习ES6【第一章】

* 一款免费观看vip会员视频神器

* 推荐一款web前端助手插件

* 一款免费的PDF在线转换神器

image

正文到此结束
本文目录