什么是浏览器缓存
浏览器缓存就是浏览器根据 url 第一次访问网站之后,将网站的 html、css、js、图片等文件复制一份保留到浏览器中,当你二次访问这个 url 的网站时,如果网站没有明确表示有更新时,浏览器直接在缓存中查找内容,不会再次请求网页内容,只有网页明确表示有更新时,浏览器才会向服务器发起网路请求,再次下载网页。
如图,百度首页就是使用了缓存机制,首次访问之后 web资源被缓存,在后面重复请求中,资源直接在缓存中读取,而不是向服务器请求资源。
为什么使用缓存
网页二次打开很快,主要原因是第一次加载页面过程中,通过将部分静态资源保存到本地这种方式,从而减少网络请求,到达提升用户体验的一种手段,这一现象,对于单页面应用开发非常明显。
浏览器缓存优点
1、减少网络带宽消耗
对于网站运营者或者访问网页的用户,带宽就代表着 money ,过多的消耗带宽,我们服务器配置就得升级,使用浏览器缓存之后,就会减少网络流量,降低运营成本。
2、降低服务器压力
使用浏览器缓存之后,除第一次访问需要向服务器请求网站全部资源,后续访问可以重复使用浏览器本地缓存,减少对服务器的请求,间接降低服务器的压力,同时,搜索引擎的爬虫也会根据缓存过期机制降低抓取的频率,也可以降低服务器压力。
3、减少网络延迟,加快网页加载
浏览器缓存 web资源后,减少网络请求,可以更快速地获取到服务器返回数据,同时使用浏览器缓存内的文件比服务器获取快很多,所以网页加载速度明显快很多。
缓存位置
分为四种,其优先级顺序如下:
1、Service Workers
2、Memory Cache(内存缓存)
3、Disk Cache(磁盘内存)
4、Push Cache
当上述四个缓存位置中的缓存都没有命中时,则会向服务器发起请求。
service worker 一句话概括,一个服务器与浏览器之间的中间人角色,如果网站中注册了service worker那么它可以拦截当前网站所有的请求,进行判断(需要编写相应的判断程序),如果需要向服务器发起请求的就转给服务器,如果可以直接使用缓存的就直接返回缓存不再转给服务器。从而大大提高浏览体验。传输协议必须为 HTTPS。因为 Service Worker 中涉及到请求拦截,所以必须使用 HTTPS 协议来保障安全。
Memory Cache 即内存中的缓存,其特点是容量小、读取高效、持续性短,会随着进程的释放而释放。所以,在内存使用率低、缓存小尺寸资源时,会以 Memory Cache 为优先,否则使用 Disk Cache。
Disk Cache 即磁盘中的缓存,其特点是容量大、读取缓慢、持续性长,任何资源都能存储到磁盘中。
所以,在内存使用率高、缓存大尺寸资源时,会以 Disk Cache 为优先。
Push Cache 是 HTTP 2.0 中的内容,其缓存时间也很短暂,只在会话(Session)中存在,一旦会话结束就被释放。
缓存过程分析
浏览器与服务器通信的方式为应答模式,即是:浏览器发起HTTP请求 – 服务器响应该请求,那么浏览器怎么确定一个资源该不该缓存,如何去缓存呢?浏览器第一次向服务器发起该请求后拿到请求结果后,将请求结果和缓存标识存入浏览器缓存,浏览器对于缓存的处理是根据第一次请求资源时返回的响应头来确定的。具体过程如下图:
由图我们可以知道:
浏览器每次发起请求,都会先在浏览器缓存中查找该请求的结果和缓存标识。
浏览器每次拿到返回的请求结果都会将该结果和缓存标识存入浏览器缓存中。
以上两点结论就是浏览器缓存机制的关键,它确保了每个请求的缓存存入与读取,只要我们再理解浏览器缓存的使用规则,那么所有的问题就迎刃而解了。
这里我们根据是否需要向服务器重新发起HTTP请求将缓存过程分为两个部分,分别是强缓存和协商缓存。
强制缓存
当浏览器发起 HTTP 请求时,会依次查找上述缓存位置中是否存在缓存资源并通过设置两种 HTTP Header缓存标识字段 Expires 或 Cache-Control 来验证缓存资源是否过期。
Expires(到期时间) 是服务器端在响应请求时用来规定资源的失效时间。Expires 是 HTTP/1 的产物,受限于本地时间,如果修改了本地时间,可能会造成缓存失效。
Cache-Control (缓存控制) 是服务器端在响应请求时用来规定资源是否需要被浏览器缓存以及缓存的有效时间等。主要用于控制网页缓存
若是命中缓存(即存在缓存资源并且缓存资源未过期),则浏览器响应 HTTP Status Code 200,并直接使用缓存资源作为返回结果,不需要向服务器发送请求,直接从缓存中读取资源,在chrome控制台的Network选项中可以看到该请求返回200的状态码,并且Size显示from disk cache或from memory cache。
若是存在缓存资源但缓存资源已过期,则进入协商缓存。
Cache-Control
Cache Cache-Control 可以在请求头或者响应头中设置,并且可以组合使用。 -Control 可以在请求头或者响应头中设置,并且可以组合使用 | |
no-cache | 客户端缓存内容,是否使用缓存则需要经过协商缓存来验证决定。表示不使用 Cache-Control的缓存控制方式做前置验证,而是使用 Etag 或者Last-Modified字段来控制缓存。 这个名字有一点歧义,并不是说浏览器不能缓存,只是浏览器在使用缓存数据时,需要先确认一下资源文件是否还跟服务器保持一致。 |
no-store | 所有内容都不会被缓存,即不使用强制缓存,也不使用协商缓存(memory cache也会失效) |
max-age | 指明缓存副本的有效时长,从请求时间开始到过期时间之间的秒数,max-age=xxx 表示缓存内容将在xxx秒后失效。比如当 Cache-Control:max-age=300时,则代表在这个请求正确返回时间(浏览器也会记录下来)的5分钟内再次加载资源,就会命中强缓存。 |
public | 所有内容都将被缓存(客户端和代理服务器都可缓存) |
private | 所有内容只有客户端可以缓存,Cache-Control的默认取值。 |
Expires 是 HTTP 1.0 的字段,而 Cache-Control 是 HTTP 1.1 的字段,当 Expires 与 Cache-Control 同时存在时,Cache-Control 的优先级要高于 Expires。
强缓存判断是否缓存的依据来自于是否超出某个时间或者某个时间段,而不关心服务器端文件是否已经更新,这可能会导致加载文件不是服务器端最新的内容,那我们如何获知服务器端内容是否已经发生了更新呢?此时我们需要用到协商缓存策略。
协商缓存
协商缓存就是强制缓存失效后,浏览器携带缓存标识向服务器发起请求,由服务器根据缓存标识决定是否使用缓存的过程。
请求的资源是否在上一次请求和这一次请求之间发生过变化。
如果发生了变化则正常发起200响应,反之则发起304响应,直接触发协商缓存,返回304和Not Modified。
协商缓存可以通过设置两种 HTTP Header,Last-Modified && If-Modified-Since或者ETag && If-None-Match实现。
Last-Modified和 If-Modified-Since(http1.0响应头和请求头)
Last-Modified 是服务器端在响应请求时用来说明资源的最后修改时间。
与之对应的是 If-Modified-Since 字段,在协商缓存过程中,浏览器发送的 HTTP 请求中Header 中会带上 If-Modified-Since 字段,值为缓存资源 Last-Modified 属性的值。这个字段对应的时间代表服务端该资源的最后一次更改时间,当客户端再一次请求该资源时,浏览器会自动为请求添加If-Modified-Since请求头,且该请求头携带上一次Last-Modified的值。
当服务器端接收到带有 If-Modified-Since 的请求头后,则会将 If-Modified-Since 的值与被请求资源的最后修改时间做对比。如果相同,说明资源没有新的修改,则响应 HTTP Status Code 304,浏览器会继续使用缓存资源;如果最后修改时间比较新,则说明资源被修改过,则响应 HTTP Status Code 200,并返回最新的资源。
Last Modified&If-Modified-Since组合由于是非常老的http1.0的规则,也是有着比较显著的缺点的。当然,我们也有更好的方式来处理这个问题那就是下面要介绍的Etag.
Etag 和 If-None-Match(http1.1响应头和请求头)
Etag 是服务器端在响应请求时用来说明资源在服务器端的唯一标识,只要资源有变化,Etag就会重新生成。
与之对应的是 If-None-Match 字段,在协商缓存过程中,浏览器在下一次加载资源向服务器发送请求时, HTTP 请求中 Header 中会带上 If-None-Match 字段,值为该缓存资源 Etag 属性的值。
当服务器端接收到带有 If-None-Match 的请求时,则会将 If-None-Match 的值与被请求资源的唯一标识做对比。如果相同,说明资源没有新的修改,则响应 HTTP Status Code 304,浏览器会继续使用缓存资源;如果不同,则说明资源被修改过,则响应 HTTP Status Code 200,并返回最新的资源。
两者之间对比:
1)在精确度上,Etag要优于Last-Modified。
Last-Modified的时间单位是秒,如果某个文件在1秒内改变了多次,那么他们的Last-Modified其实并没有体现出来修改,但是Etag是服务器自动生成或开发者生成对应资源在服务器的唯一标识符,每次都会改变确保了精度,能够更加精准控制缓存。
如果本地打开缓存文件,即使没有对文件进行修改,但还是会造成 Last-Modified 被修改,服务端不能命中缓存导致发送相同的资源。
2)在性能上,Etag要逊于Last-Modified,毕竟Last-Modified只需要记录时间,而Etag需要服务器通过算法来计算出一个hash值。
3)在优先级上,服务器校验优先考虑Etag
两者可以一起使用,服务器优先验证ETag,一致时,才会继续比对Last-Mofifed,才决定是否要返回304。Last-Modified 是 HTTP 1.0 的字段,而 Etag 是 HTTP 1.1 的字段,当 Last-Modified 与 Etag 同时存在时,Etag 的优先级要高于 Last-Modified。
缓存机制
强制缓存优先于协商缓存进行
若强制缓存(Expires/Cache-Control)生效则直接使用缓存,若不生效则进行协商缓存(Last-Modified / If-Modified-Since和Etag / If-None-Match),协商缓存由服务器决定是否使用缓存,若协商缓存失效,那么代表该请求的缓存失效,返回200,重新返回资源和缓存标识,再存入浏览器缓存中;生效则返回304,继续使用缓存。
Cache-Control / Expires 检测本地缓存是否还在有效期内,在有效期内,直接使用本地缓存,阻止发送请求。
配置Last-Modified/ETag的情况下,浏览器再次访问URL的资源,还是会发送请求到服务器,询问文件是否已经修改,如果没有,服务器会给浏览器返回304,浏览器直接从本地缓存中取就好了,反之,服务器会直接向浏览器返回数据。
如果同时设置,Cache-Control / Expiress 优先级更高。
一般情况下,两者配合使用,因为即使服务器设置缓存时间, 当用户点击“刷新”按钮时,浏览器会忽略缓存继续向服务器发送请求,这时Last-Modified/ETag将能够很好利用304,从而减少响应开销。
不能缓存的请求
并不是所有的请求都能被缓存,无法被缓存的有:
post 请求无法被缓存。
需要根据cookie、认证信息等决定输入内容的动态请求不能被缓存。
http响应头中不包含Last-Modified/ETag,也不包含Cache-Control/Expiress的请求无法被缓存。
http信息头明确设置Cache-Control:no-cache,pragma:no-cache或Cache-Control:max-age=0浏览器不缓存时。
怎么主动清除缓存(敲黑板)
使用缓存有什么弊端?凡事有利必有弊,缓存也是。使用缓存最大的问题就是如果资源有更新,如果不采取相应措施的话,我们在访问的时候就很可能获取不到最新的资源。如何清除浏览器缓存?
使用 ctr + F5 强制刷新之后,立马就好了。或者清除浏览器缓存,按住ctr+shift+delete,在弹出窗选择清除缓存。
1.针对谷歌浏览器用户
点击右上角的“菜单”从“更多工具”找到“清除浏览数据”,后点击清除数据。
按F12或者鼠标右键,选择检查,就打开我们的“开发者面板”了。
这个时候有两种方式可以可以清理本地缓存
第一种方式:找到网页左上角的刷新图标,点击鼠标右键,点击清空缓存并硬性重新加载(只能在打开开发者面板的时候右键打开)
第二种方法:是在开发者面板切换到Network,将Disable cache勾上,再刷新,缓存就被清除了,而且浏览器就永远不会缓存文件了
当然,后面如果觉得加载速度慢可以把Disable cache去掉~
2.针对火狐浏览器用户
同样提供两种方法
第一种:是在浏览器工具栏找到工具按钮,一次点击打开应用程序菜单→设置→隐私与安全→Cookie 和网站数据→清除数据,在弹出的清除数据框中,将Cookie和网站数据那个选项去掉,否则可能要重新登陆了哦~
第二种:办法也是按F12或者鼠标右键,选择检查,或者在浏览器右上角→更多工具→web开发者→Web开发者工具,然后切换到网络面板,同样是将禁用缓存勾上,然后刷新,同样可以达到清理缓存的目的,之后就可以将禁用缓存的勾去掉了。
是否禁用缓存一般视网络情况而定,网络差缓存就比较有必要了~
下面用一张流程图来完整说明当浏览器发起HTTP请求时缓存机制的过程: