# 5、浏览器缓存
# 浏览器缓存位置
TIP
Memory Cache
:内存缓存,窗口关闭就会消失Disk Cache
:磁盘缓存,也就是存储在硬盘中的缓存,读写速度慢,比Memory Cache
胜在容量和存储时效性上。
浏览器有三级缓存原理
- 1、先找内存,如果内存中存在,从内存中加载
- 2、内存中未找到,再找硬盘,硬盘中存在,从硬盘中加载
- 3、硬盘中未找到,进行网络请求,加载到的资源缓存到硬盘和内存中
# 浏览器会把哪些文件丢进内存中,哪些丢进硬盘中?
TIP
对于大文件来说,是不会存在内存中的,反之优先。 当前系统内存使用率高的话,文件优先存进磁盘中。
# 浏览器的缓存策略
通常浏览器的缓存策略有两种:强制缓存 和 协商缓存,并且缓存策略都是通过
HTTP header
来实现的。
# 强缓存
强缓存
当用户第一次访问页面之后,浏览器将数据缓存起来,在过期时间内,都不会请求服务器,而是直接去读取缓存中的内容。过期时间从第一次请求的响应头中获取。在过期时间内,从缓存中读取,超出过期时间,则会使用协商缓存。在chrome控制台的Network选项中可以看到请求返回200的状态码(灰色),并且Size显示 form disk cache 或 form memory cache。
强缓存可以通过设置两种HTTP Header
来实现:
Expires
Cache-control
(优先级高于Expires
)
# Expires
http1.0
的产物,缓存的过期时间,用来指定资源的到期时间,是服务器端的具体时间点,浏览器发送请求时会根据系统时间和Expires
的值进行对比,由于是和系统时间作比较,所以会有缓存有效期不准的问题(已不推荐使用)。也就是说,Expires = max-age + 请求时间
,需要和Last-Modified
结合使用。Expires
是Web
服务器响应消息头字段,在响应http
请求时告诉浏览器在过期时间前浏览器可以直接从浏览器缓存取数据,而无需再次请求。
# Cache-Control
Cache-Control
http1.1
的产物,控制缓存的行为,常用属性值如下:
max-age
:单位为妙,多少秒后失效no-cache
:不使用强缓存,需要与服务器验证缓存是否新鲜no-store
:禁止使用缓存(包括协商缓存),每次向服务器请求最新的资源private(默认值)
:专用于个人的缓存,中间代理、CDN等不能缓存此响应,max-age
存在时则会验证是否过期public
:响应可以被中间代理、CDN缓存must-revalidate
:在缓存过期前可以使用,过期后必须向服务器验证
# Expires和Cache-Control的区别
最大的区别就是
Expires
是http1.0
的产物,而Cache-Control
是http1.1
的产物,两者同时存在的话Cache-Control
优先级是高于Expires
的。强缓存判断是否缓存的依据来自于是否
超出某个时间或某个时间段
,而不关心服务器端文件是否更新。因此才有了协商缓存策略;
# 协商缓存
当强缓存失效后,浏览器携带缓存标识向服务器发送请求,由服务器根据缓存标识决定是否使用缓存。 协商缓存可以通过设置
HTTP Header
来实现:
Last-Modified
Etag
(会优先验证Etag)
# Last-Modified 和 If-Modified-Since
TIP
浏览器在第一次访问资源时,服务器返回资源的同时,在response header
中会添加Last-Modified
的header
,值为这个资源在服务器上最后的修改时间,浏览器接收后缓存资源和header
。
浏览器下一次请求时,当强缓存已过期,且检测到有Last-Modified
这个header
,就会在请求中添加If-Modified-Since
这个header
,值就是Last-Modified
的值,服务器再次收到这个资源请求,就会根据If-Modified-Since
这个值与服务器中这个资源的最后修改时间做对比,如果没有变化,就返回304
、新的header
和空响应体,直接从缓存中读取。如果资源修改了,就会返回新的资源和新的过期时间。
Last-Modified
存在的弊端:
Last-Modified
只能以秒为单位计时,如果文件的修改频率在秒级以下,这样的话,Last-Modified
就不再准确;- 有些文档可能会被周期性的重写,尽管内容没有发生变化,但
Last-Modified
会发生变化。
# Etag 和 If-None-Match
TIP
为了解决Last-Modified
存在的弊端,HTTP1.1
推出了Etag
和 If-None-Match
。Etag
是服务器响应请求时,返回当前资源的实体标签(由服务器生成,可以是文档的序列号或版本名,或者是文档内容的校验和及其他指纹信息),当发布者对文档进行修改时,可以修改文档的实体标签来说明这个新的版本,这样,缓存就可以用If-None-Match
来检验资源是否被修改过。
浏览器在下次发送请求时,就会将Etag
的值放在请求头header
的If-None-Match
中。服务器会比对If-None-Match
的值和该资源的Etag
值是否一致,如果一致,说明未修改,返回304,浏览器继续使用缓存。如果不一致,返回200以及新的资源和Etag
;
Etag 和 Last-Modified 用哪个?
给哪个用哪个,如果两个都给,则只有Etag
不变,且Last-Modified
与服务器一致的时候才能返回304 Not Modified
;
# 如果什么缓存策略都没设置,那么浏览器会怎么处理?
浏览器会采用一个启发式的算法,通常会取响应头中的
Date
减去Last-Modified
值的10%
作为缓存时间。
# 用户行为对缓存的影响
意思是用户行为会如何触发缓存策略
- 用户输入
url
,查找disk cache
,是否有匹配,有则直接使用,没有则发送请求;- 普通刷新(F5):因为窗口并没有关闭,因此
memory cache
依然是可用的,会被优先使用(如果匹配的话)。其次才是disk cache
。- 强制刷新(Ctrl+F5):浏览器不使用缓存。因此发送请求头部均带有
Cache-Control:no-cache
,服务器直接返回200
和最新内容;
# 缓存总结
当浏览器需要资源时
- 1、调用
Service Worker
的fetch
事件响应 - 2、查看
memory cache
- 3、查看
disk cache
,这里会细分:- 有强缓存且未失效,则使用强制缓存,返回
200
- 有强制缓存已失效,则使用协商缓存,可用返回
304
,不可用返回新数据和200
- 有强缓存且未失效,则使用强制缓存,返回
- 4、向服务器发送请求,等待响应
- 5、把响应内容存入
disk cache
(如果HTTP
头信息配置可存) - 6、把 响应内容的引用 存入
memory cache
(无视HTTP
头信息的配置) - 7、把响应内容存入
Service Worker
的Cache Storage
(如果Service Worker
的脚本调用了cache.put()
)
# Transfer-Encoding
指定报文主体的传输编码方式