引言
WEB 缓存知识体系:
浏览器从输入URL到界面展示的流程:
一、浏览器缓存
浏览器缓存是为了节约网络的资源加载浏览,浏览器在用户磁盘上对最近请求过的文档(html、css、js、image等静态资源)进行存储,当访问者再次请求这个页面时,浏览器就可以从本地磁盘显示文档,这样就可以加速页面的阅览。
注意点: HTTP缓存是浏览器缓存的核心。一般意义来讲,浏览器缓存是指HTTP缓存。严格意义来讲,浏览器缓存 = HTTP缓存 + 数据缓存。
1.1 缓存位置
强缓存我们会把资源放到 memory cache 和 disk cache中。
存储图像和网页等资源主要缓存在disk cache,操作系统缓存文件等资源大部分都会缓存在memory cache中。具体操作浏览器自动分配,看谁的资源利用率不高就分给谁。
查找浏览器缓存时会按顺序查找: Service Worker-->Memory Cache-->Disk Cache-->Push Cache。
1.1.1 Service Worker
是运行在浏览器背后的独立线程,一般可以用来实现缓存功能。使用 service worker 的话,传输协议必须为 HTTPS。因为 Service Worker 中涉及到请求拦截,所以必须使用 HTTPS 协议来保障安全。
Service Worker 的缓存与浏览器其它内建的缓存机制不同,它可以让我们自由控制缓存哪些文件?如何匹配缓存?如何读取缓存,并且缓存是持续性的
1.1.2 memory cache
MemoryCache,内存中的缓存。就是将资源缓存到内存中,等待下次访问时不需要重新下载资源,而直接从内存中获取,读取速度快且高效。但它是短暂的,当浏览器或Tab页面关闭,内存就会被释放。
Webkit早已支持memoryCache。 目前Webkit资源分成两类,一类是主资源,比如HTML页面,或者下载项,一类是派生资源,比如HTML页面中内嵌的图片或者脚本链接,分别对应代码中两个类:MainResourceLoader和SubresourceLoader。虽然Webkit支持memoryCache,但是也只是针对派生资源,它对应的类为CachedResource,用于保存原始数据(比如CSS,JS等),以及解码过的图片数据。
1.1.3 disk cache
DiskCache顾名思义,就是将资源缓存到磁盘中,等待下次访问时不需要重新下载资源,而直接从磁盘中获取,它的直接操作对象为CurlCacheManager。
-
Memory Cache 和 Disk Cache
-
相同点
- 只能存储一些派生类资源文件
-
不同点
- Memory Cache 退出进程时数据会被清除
- Disk Cache退出进程时数据不太会被清除
-
存储资源
- Memory Cache 一般脚本、字体、图片会存在内存当中
- Disk Cache 一般非脚本会存在内存当中,如CSS
因为CSS文件加载一次就可渲染出来,我们不会频繁读取它,所以它不适合缓存到内存中,但是js之类的脚本却随时可能会执行,如果脚本在磁盘当中,我们在执行脚本的时候需要从磁盘取到内存中来,这样IO开销就很大了,有可能导致浏览器失去响应。
-
-
prefetch cache(预期缓存)
prefect cache 是预加载的一种方式,被标记为 prefect 的资源,将会被浏览器在空闲时间加载
link 标签上带了 prefect,再次加载会出现
1.1.4 Push Cache
Push Cache(推送缓存)是HTTP2.0 中的内容,当以上三种缓存都没有命中,它才会被使用。它只在会话(session)中存在,一旦会话结束就被释放,并且缓存时间也很短暂,在Chrome浏览器中只有5分钟左右,同时它也并非严格执行HTTP头中的缓存指令。
三级缓存原理 (访问缓存优先级)
- 先在内存中查找,如果有,直接加载。
- 如果内存中不存在,则在硬盘中查找,如果有直接加载。
- 如果硬盘中也没有,那么就进行网络请求。
- 请求获取的资源缓存到硬盘和内存。
二、数据缓存
数据缓存方式:cookie、localStorage、sessionStorage、IndexedDB、Web SQL
2.1 cookie
-
优点:访问方便,使用方便,且还有多个属性可以设置
-
缺点:
- 大小受限,只有4KB左右;
- 明文传递,存在安全风险;
- 客户端还可以禁用;不能跨域
-
设置方式:通过JS设置或服务器的response header设置
-
应用场景:接口请求中的身份认证
-
自动删除场景:
- 会话cookie会在游览器关闭时删除
- 持久cookie会在到达失效日期时删除
- 游览器中的cookie数量达到限制时会删除旧的cookie为新建cookie创建空间
2.2 localStorage 和 sessionStorage
-
localStorage和sessionStorage是为了解决cookie的存储空间不足的问题 -
相同点
- HTML5新增的特性
- 存储大小一般均为5M左右。localStorage实际上是主要跟各厂家游览器有关,是在2.5~10MB之间
- 访问策略:都有同源策略限制,跨域无法访问
- 存储位置:数据仅在客户端中保进行存储,并不参与和服务器的通信(不会随着 http 请求发送到服务器)
- 存储形式:以 key 和 value 的形式进行存储数据, value 值必须为字符串,不为字符串会自动转型( value 如果是对象则需要转为 json 进行存储)
-
不同点
-
存储类型:
- localStorage:本地存储
- sessionStorage:会话存储
-
生命周期:
- localStorage:存储的数据是永久性的。除非人为清除,
- sessionStorage:随游览器窗口/标签页关闭而删除,或人为清除。
-
作用域:
-
localStorage:在同一个浏览器内,同源文档之间共享 localStorage 数据,可以互相读取、覆盖、清除(同浏览器限制、同源限制)
- 在同一浏览器下,打开了两个浏览器标签页,对应的页面都是 http://localhost:8090/A 这两页签在localStorage中存储的数据是可以同步共享使用的
- http://localhost:8090/A 和 http://localhost:8090/B A、B页面在localStorage中存储的数据是可以同步共享使用的
-
sessionStorage:有同一浏览器、同一窗口的同源文档才能共享数据(同浏览器限制、同源限制、同标签页限制),或包含多个iframe标签页且他们属于同源页面
-
-
-
新增/修改(它们的方式都是有一样的,就以sessionStorage为例)
-
通过 setItem 添加、修改数据
sessionStorage.setItem('name', 'qianyin'); sessionStorage.setItem('name', 'linheng'); sessionStorage.setItem('user1', {name: 'qianyin'}); sessionStorage.setItem('user2', JSON.stringify({name: 'qianyin'})); -
通过对象的形式添加、修改数据
sessionStorage.name = 'qianyin'; sessionStorage.name = 'linheng'; sessionStorage.user1 = {name: 'qianyin'}; sessionStorage.user2 = JSON.stringify({name: 'qianyin'}) -
通过浏览器(chrome)控制台查看数据
-
-
获取数据(它们的方式都是有一样的,就以sessionStorage为例)
-
通过 getItem 获取数据
sessionStorage.getItem('user') -
通过对象的形式获取数据
sessionStorage.user -
通过 length 属性存储数量
sessionStorage.getItem('user')
-
-
移除数据(它们的方式都是有一样的,就以sessionStorage为例)
-
通过 removeItem 移除指定数据
sessionStorage.removeItem('user'); -
通过对象的形式移除指定数据
delete sessionStorage.user -
移除当前作用域下所有数据
sessionStorage.clear();
-
2.3 IndexedDB
游览器提供的本地数据库
-
特点
- 键值对存储,IndexDB内部采用对象仓存放数据库,每条数据对应一个主键,主键唯一,否则报错
- 异步操作
- 支持事务,操作中某步骤发生错误后整个事务取消,数据库回滚至事务之前的状态
- 同源策略,网页只能访问自身域名下的数据库,而不能访问跨域的数据库
- 存储空间大,>= 250MB
- 支持二进制,既可以存储字符串,也可以存储二进制
2.4 Web SQL
HTML5本地数据库
-
使用场景:适用于移动端,尤其是Hybrid应用
-
特点
- 事务事件
- 查询数据,返回数据类型正确
- 被W3丢弃的规范,但被广泛使用
三、HTTP缓存
-
作用(优点):
- 减少冗余的数据请求,节省网络带宽。过多的带宽消耗会增加运营成本,当Web缓存副本被使用时,只会产生极小的网络流量,可以有效的降低运营成本。
- 节省网络资源,降低服务器压力。在发起请求时,会根据缓存机制决定是直接使用副本还是重新请求。从而减少对源服务器的请求,间接降低服务器的压力
- 减少网络延迟,加快打开速度。直接取缓存的副本速度会重新请求的速度快,从视觉效果上,能明显加快页面打开速度,达到更好的用户体验。
-
资源缓存位置: 浏览器获取缓存的顺序为 Service Worker Cache、Memory Cache、Disk Cache
from Memory Cache: 是把资源存在内存中,当进程退出时(关闭浏览器),内存中的数据会被清空,下次访问要执行别的缓存策略。from disk cache: 是把资源缓存在磁盘中,进程退出时不受影响,下次访问可以继续执行此次缓存策略。Sevice Worker Cache(https): 开发者认为存储的永久性存储,用于离线缓存的处理
-
缺点:
- 占内存(有些缓存会被存在内存中)
-
缓存策略:
- 强缓存。不需要发请求询问服务器直接取本地缓存资源。
- 协商缓存。需要发请求询问服务器,命中后返回304,取本地缓存资源,没有命中服务器就会返回最新资源。
【相同点】 :使用的都是浏览器缓存到本地的资源 【不同点】 :强缓存不会发起网络请求,协商缓存会发起网络请求
3.1 强制缓存(强缓存)
- 什么是强缓存 主要是浏览器自行判断资源是否过期,如果不过期则直接使用缓存的资源(强缓存命中),不再进行网络请求。
- 强缓存的实现 利用
Expires或者Cache-Control这两个http response header实现的,它们都用来表示资源在客户端缓存的有效期。
3.1.1 Expires(优先级最低)
- http1.0 用于缓存管理的
header字段,由服务器返回,用GMT格式的字符串表示 - 值表示一个资源过期的时间,描述的是绝对时间,且该绝对时间属于服务端的时间系统
- 判断方法:浏览器发起下一次请求时,当前http发起的
请求时间(this http request time) < expires设置的值,资源没有过期,缓存命中 - 弊端:Expires遵循的是服务端的时间系统,而请求时间遵循的是客户端的时间系统,如果两者时间不是一致的,就可能产生误差。例如手动修改本地客户端的时间,那么就可能影响缓存命中结果。
- 已被弃用!已被 Cache-Control 替代!在不支持 Cache-Control 的情况下还是可以继续使用这个属性的
3.1.2 Cache-Control(优先级第二)
为了解决Expires因为客户端和服务器端时间不统一带来的问题,HTTP 1.1 提出了新的header 也就是 Cache-Control ,这个字段使用相对时间,进行比较的时候用的都是客户端的时间,相对来更有效与安全。
-
http1.1
-
允许你定义响应资源应该何时、如何被缓存以及缓存多长时间的组成
-
值是一个相对时间,以秒为单位,用数值表示。从第一次请求资源的时候开始,往后N秒内,资源若再次请求,则直接从本地缓存读取,不与服务器做任何交互。
-
判断方法:浏览器发起下一个请求时,当前HTTP发起的
请求时间(this http request time) < (last http request time + cache-control 设置的值),资源没有过期,缓存命中。cache-control: max-age=315360000 -
字段值取值
- no-cache: 请求头/响应头。强制客户端向服务器发送请求。这个值不是禁止客户端或代理服务器缓存响应(表示禁止强缓存,强制进行协商缓存)
- no-store: 请求头/响应头。禁止一切缓存。客户端和代理服务器都不能缓存响应(表示禁止任何缓存策略)
- max-age: 请求头/响应头。设置资源(representations)可以被缓存多长时间,单位是秒,时间是相对于请求的时间(决定客户端资源被缓存多久)
- no-transform: 请求头/响应头。代理不可更改媒体类型。
- cache-extension: 请求头/响应头。新指令标记(token)。
- s-maxage: 响应头。和max-age同理,只不过是针对代理服务器缓存而言(决定服务器缓存的时长)
- private: 响应头。不能被代理服务器缓存(表示资源只能被浏览器缓存)
- public: 响应头。响应可以被任何缓存区缓存(表示资源可以被浏览器缓存也可以被代理服务器缓存)
- must-revalidate: 响应头。在缓存过期前可以使用,缓存过期以后必须向服务器验证。
- proxy-revalidate: 响应头。要求中间缓存服务器对缓存的响应有效性需再次确认(代理服务器需要发送请求给服务器端确认资源有效性,不能直接返回缓存)
- only-if-cached: 请求头。从缓存中获取资源
- min-fresh: 请求头。单位:秒,期望在指定的时间内,响应仍有效
- max-stale: 请求头。单位:秒, 接受已过期的响应
-
no-cache 与 no-store 的区别
- no-cache: 强制进行协商缓存
- no-store: 禁止所有的缓存策略
- 是一组互斥属性,不能同时出现在 cache-control 中
-
public 与 private 决定资源是否可以在代理服务器进行缓存。默认值是 private
- public: 表示资源在客户端和代理服务器都可以被缓存
- private: 表示资源只能在客户端被缓存,拒绝资源在代理服务器缓存
- 是一组互斥属性,不能同时出现在 cache-control 中
-
max-age 与 s-maxage
- max-age: 表示的是资源在客户端缓存时长
- s-maxage: 表示的是资源在代理服务器可以缓存时长。必须和 public 一起使用。
- 不互斥,可以同时使用
参考: - 图文讲解 Cache-Control 浅显易懂 - Cache-Control_MDN
3.1.3 Pragma(优先级最高)
只有一个值就是 no-cache,含义等同于 Cache-Control 取值为 no-cache,表示禁止强缓存,强制客户端发送http请求给客户端。
- Pragma在HTTP 响应中的行为没有确切规范,所以尽量少用
参考:
3.2 协商缓存
-
什么是协商缓存 在强缓存阶段无法命中的情况下,浏览器发起请求,询问服务器是否可以使用本地缓存资源,如果服务器检查发现浏览器本地的资源没有过期,则返回304告诉浏览器可以继续使用本地的缓存资源(协商缓存命中)。就是需要服务器确定是否使用本地缓存资源的缓存策略。
-
协商缓存方案
- Last-Modified / If-Modified-Since
- Etag / If-None-Match
3.2.1 Last-Modified / If-Modified-Since
-
资源最后的修改时间
-
缓存实现方式: 1)首先需要在服务器端读出文件修改时间 2)将读出来的修改时间赋给响应头的
Last-Modified字段 3)最后设置Cache-control:no-cache -
浏览器发送请求时,会将上次响应头中的
Lasr-Modified赋值给本次请求头中的If-Modified-Since字段。服务端中接收到请求之后,会将这个字段和当前资源最后的修改时间做对比,- 如果
If-Modified-Since(上一次资源修改时间) < 服务器上资源的最后修改时间,则说明当前资源被修改过了,服务端需要返回新的资源给服务端,此时响应200,返回正常的响应。同时这次响应会返回新的Last-Modified值,用于更新浏览器缓存 - 如果
If-Modified-Since(上一次资源修改时间) ≥ 服务器上资源的最后修改时间,则说明没有修改过资源,则返回304状态码,不会返回资源内容。
- 如果
-
弊端: 1)短时间内资源发生了变化,这个字段并不会发生变化,缓存命中可能失效。文件修改时间记录的最小单位是秒,而文件是在几百毫秒内完成修改,那么文件修改时间不会改变,这样,即使文件内容修改了,依然不会返回新的文件 2)如果出现了服务器资源因为反复修改,但资源内容并没发生变化,此时浏览器再次请求服务器,实际上应该认为缓存命中(实际内容没有变化),但是此时通过该字段的比较会导致缓存命中失效。
3.2.2 Etag / If-None-Match
文件指纹: 根据文件内容计算出的唯一哈希值。文件内容一旦改变则指纹改变。
- Etag是Last-Modified的补充方案(为了解决
Last-Modified的缓存命中问题,可以通过Etag来管理协商缓存命中) - 该字段是当前资源在服务器的唯一标识(生成规则由服务器决定),是基于文件内容进行编码的,如果文件内容不发生变动,那么该表示不会发生变更
- 服务端收到响应以后,根据当前资源内容重新生成一份
Etag,比较该值和If-None-Match是否相等,相等则返回304,不相等则返回200和正常响应。但同Last-Modified的区别在于即使服务器重新生成的Etag字段和原来的没有变化,但是因为重新生成了,304响应中同样会返回Etag字段。 - 弊端: 1)ETag需要计算文件指纹这样意味着,服务端需要更多的计算开销。。如果文件尺寸大,数量多,并且计算频繁,那么ETag的计算就会影响服务器的性能。显然,ETag在这样的场景下就不是很适合。 2)ETag有强验证和弱验证,所谓将强验证,ETag生成的哈希码深入到每个字节。哪怕文件中只有一个字节改变了,也会生成不同的哈希值,它可以保证文件内容绝对的不变。但是,强验证非常消耗计算量。ETag还有一个弱验证,弱验证是提取文件的部分属性来生成哈希值。因为不必精确到每个字节,所以他的整体速度会比强验证快,但是准确率不高。会降低协商缓存的有效性。
四、DNS缓存
参考:DNS缓存
-
什么是DNS
-
DNS概念:
-
DNS:Domain Name System ,即域名系统。
-
DNS是一个由分层的DNS服务器实现的分布式数据库。
整个DNS系统由分散在世界各地的很多台DNS服务器组成,每台DNS服务器上都保存了一些数据,这些数据可以让我们最终查询到主机名对应的IP。
什么是分布式:这个世界上没有一台DNS服务器拥有因特网上所有主机的映射,每台DNS只负责部分映射
-
DNS是一个使得主机能够查询分布式数据库的应用层协议.
用户端发送一个请求,其中包含我们要查询的主机名,它就会给我们返回这个主机名的IP。
DNS协议是运行在UDP协议之上,使用端口号53.
-
-
DNS服务器
示例:www.baidu.com 的完整写法是 www.baidu.com. 。最后的那个. 是根域名;com是顶级域名。
DNS的层次结构:根DNS服务器 - 顶级域DNS服务器 - 权威DNS服务器。
-
根DNS服务器
- 作用:管理它的下一级,也就是顶级域DNS服务器。
-
顶级域DNS服务器(TLD)
- 作用:提供了它的下一级,也就是权威DNS服务器的IP地址
- 常见的顶级域名:com、cn、org、edu等
-
权威DNS服务器
- 作用:返回 主机 - IP 的最终映射
-
-
DNS缓存的作用:
- 为了更快的拿到IP地址
-
-
本地DNS服务器 严格讲,本地DNS服务器并不属于DNS的层次结构,但是它对DNS层次结构至关重要。
- 什么是本地服务器:每个ISP都有一台本地DNS服务器,比如一个居民区的ISP、一个大学的ISP、一个机构的ISP,都会有一台或多台本地DNS服务器。当主机发出DNS请求时,该请求被发往本地DNS服务器,本地DNS服务器起着代理的作用,并负责将该请求转发到DNS服务器层次结构中。
-
DNS解析
- 简单的说,通过域名,最终得到该域名对应的IP地址的过程叫做域名解析(或主机名解析)。
www.baidu.com (域名) - DNS解析 -> 111.222.33.444 (IP地址)-
DNS查询过程:
- 主机
m.n.com向它的本地DNS服务器发送一个DNS查询报文,其中包含期待被转换的主机名a.b.com - 本地DNS服务器将该报文转发给DNS服务器;
- 该根服务器注意到
com前缀,便向本地DNS服务器返回com对应的顶级域DNS服务器(TLD)的IP地址列表。(意思是,不知道a.b.com的IP,不过这些TLD服务器可能知道,你去问他们吧~) - 本地DNS服务器则向其中一台TLD服务器发送查询报文;
- 该TLD服务器注意到
b.com的前缀,便向本地DNS服务器返回权威DNS服务器的IP地址。(意思是,不知道a.b.com的IP,不过这些权威服务器可能知道,你去问问那他们吧~) - 本地DNS服务器又向其中一台权威服务器发送查询报文;
- 终于,该权威服务器返回了
a.b.com的IP地址 - 本地DNS服务器将
a.b.com根IP地址的映射返回给主机m.n.com,m.n.com就可以用该IP向a.b.com发送请求啦~
- 主机
-
DNS解析过程:
- 1)首先搜索浏览器自身的DNS缓存,如果存在,则域名解析到此为止;
- 2)如果浏览器自身的缓存里没找到对应的条目,那么会尝试读取操作系统的hosts文件,查看是否存在对应的映射关系,如果存在,则域名解析到此为止;
- 3)如果本地hosts文件不存在映射关系,则查找本地DNS服务器,如果存在,域名解析到此为止;
- 4)如果本地DNS服务器未找到的话,它就会向根服务器发出请求,进行递归查询。
-
DNS缓存分类
- 浏览器DNS缓存
- 应用程序DNS缓存
- 操作系统DNS缓存
- DNS缓存服务器
五、CDN缓存
CDN: Content Delivery Network,内容分发网络
CDN缓存
关于CDN缓存,在浏览器本地缓存失效后,浏览器会向CDN边缘节点发起请求。类似浏览器缓存,CDN边缘节点也存在着一套缓存机制。CDN边缘节点缓存策略因服务商不同而不同,但一般都会遵循http标准协议,通过http响应头中的
Cache-control: max-age //后面会提到
复制代码
的字段来设置CDN边缘节点数据缓存时间。
当浏览器向CDN节点请求数据时,CDN节点会判断缓存数据是否过期,若缓存数据并没有过期,则直接将缓存数据返回给客户端;否则,CDN节点就会向服务器发出回源请求,从服务器拉取最新数据,更新本地缓存,并将最新数据返回给客户端。 CDN服务商一般会提供基于文件后缀、目录多个维度来指定CDN缓存时间,为用户提供更精细化的缓存管理。
CDN优势
- CDN节点解决了跨运营商和跨地域访问的问题,访问延时大大降低。
- 大部分请求在CDN边缘节点完成,CDN起到了分流作用,减轻了源服务器的负载。