HTTP 缓存是一块重要的内容,这是作为一个前端工程师必须要掌握的优化技能,也能让自己明白自己的工作,此次主要分了几个点进行总结
浏览器缓存策略
浏览器对于请求资源,拥有一系列成熟的 缓存策略
1、存储策略
确定 HTTP 响应内容是否可以被客户端缓存,可以被哪些客户端缓存
相关首部 设置
Cache-Control:no-cache Pragma:no-cache
2、过期策略
根据存储时间判断本地缓存是否过期,是否需要重新请求
相关首部 设置
Cache-control:max-age=100,min-fresh=100,max-stale=100 Expires : Mon, 13 Aug 2018 03:40:08 GMT
3、协商策略
重新向服务器发起验证,查证缓存是否过期
相关首部 设置
if-Modified-Since, if-unmodified-since, last-modified if-match, if-none-match, etag
缓存相关首部
1.Cache-Control
霸道总裁:其他设置有相同,一律覆盖
杂交规则:可以同时设置很多种值,包含存储策略,过期策略
Cache-Control:max-age=10,min-fresh=10,max-stale=10
max-age | 覆盖默认时间,缓存 10 s |
---|---|
max-stale | 增加默认过期时间,在 10 s内,缓存可以过期 |
min-fresh | 减少默认过期时间,最后 10 s,缓存不能过期 |
Cache-Control 还有很多其他值,但是我过滤了一些
Cache-Control:no-cache,no-store,must-revalidate
public | 被客户端和 代理服务器 缓存 |
---|---|
private | 只被客户端缓存,代理服务器不缓存 |
no-cache | 防止从缓存中返回过期的资源,缓存会向源服务器进行有效确认后处理资源其实不是不让你缓存到本地,而是让你每次请求都不会马上本地缓存获取,而是确认一遍 |
no-store | 请求和响应都不缓存 |
only-if-cached | 要求 只返回已经缓存的资源,不用访问网络,无缓存就返回504 |
must-revalidate | 可缓存,但是必须向原服务器确认 |
2.Pragma
http1.0 字段,现在为了向后兼容,也是指定缓存机制
Pragma:no-cache
3.Expires
http1.0 字段,为了向后兼容,指定 缓存时间
Expires: Mon, 13 Aug 2018 03:40:08 GMT
4.Last-Modified
资源最后一次修改时间,以此判断资源是否更新
Last-Modified: Thu, 09 Aug 2018 10:42:13 GMT
5.Etag :
资源唯一标志,修改之后,标志会相应更新,以此判断资源是否更新
浏览器根据Etag 值缓存数据, 节省带宽
Etag 比 Last-Modified 级别要高
ETag:"fcb82312d92970bdf0d18a4eca08ebc7efede4fe"
6.If-Modified-Since,If-Unmodified-Since
主要也是为了判断资源是否更新过
两个首部的值都是是上次响应收到的 Last-Modified 的值
If-Modified-Since
If-Modified-Since 时间后 被修改,返回200
没有被修改,返回304
If-UnModified-Since
If-UnModified-Since 时间后 未修改,返回 200
被修改,返回 412 Precondition failed 预处理错误
主要用于断点续传,肯定要保证文件没有修改
7.If-Match, If-None-Match
主要也是为了判断资源是否更新过
两个首部的值都是是上次响应收到的 Etag 值
If-Match
如果和 请求资源的 ETag 一样,返回200
如果不一样,返回 412
If-None-Match
如果和 请求资源的 ETag不一样,返回 200
如果一样,返回304
缓存类型
强缓存
一旦命中强缓存,浏览器就不会发送请求,而是直接读取缓存。
Chrome 下是 200 OK (from disk cache) 或者 200 OK (from memory cache)
只要存在缓存,而且 Cache-Control 和 Expires 没有过期,那么都能命中缓存
协商缓存
缓存过期了,需要重新请求资源,有两种做法
1、判断 ETag 是否改变
1、浏览器把上次响应的 Etag 的值,填入这次请求的 If-None-Match
2、服务器收到请求,拿 If-None-Match 字段 和 服务器资源的 Etag 对比,若相同,命中协商缓存,返回304
2、判断 Last-MOdified 是否改变
1、浏览器把上次响应的 Last-Modified,填入这次请求的 If-Modified-Since
2、服务器收到请求,拿 If-Modified-Since 和 服务器资源的 Last-Modified 比较,如果相同,命中协商缓存,返回304
304 到底有什么用?? 当客户端缓存了目标资源,但是不确定是否是最近的版本,会发一个条件请求,附带上 条件首部 服务器拿到首部,判断出客户端的资源是否是最新的 如果是最新的,返回304,但是没有响应体,客户端收到304,就会从缓存中读取对应的值 如果不是最新的,返回200,返回最新的内容,客户端使用新的响应体 覆盖 旧的响应体 可以节省网页的打开时间,有机会省去整个响应体的发送 条件请求的触发条件
缓存资源类型
1、文件可以缓存,比如 js、css、json
2、post 无法缓存,get 请求可以缓存
3、还有其他的我不知道.......
通过测试,可以知道,缓存放在两个位置
一个是 disk,一个是 memory
而同样是 reset.css,通过 link 引入,和 通过 ajax 请求,缓存存放的位置是不一样的
下面是 link 引入reset.css
下面是 ajax 引入reset.css
而 ajax 请求接口的数据,也是放在 disk
所以,可以得出
1、ajax 请求的缓存都放在 disk
2、 页面引入的 js、css 都放在 memory
缓存过期时间计算
响应返回 Cache-Control:
当同时添加 max-stale,min-fresh,max-age,他们之间相互独立
并不会谁一定覆盖谁,而是看谁最后计算得到的 保存时间最短,到最后使用谁
比如 资源在 今天 8:00:00 缓存,今天8:00:50 过期,也就是说默认 缓存时间为 50s
现在,我们添加一个 缓存时间变量 cache_time
第一种设置
max-age=10,那么 cache_time= 10
max-stale=5,那么 cache_time= 50+5 = 55
max-fresh=2,那么 cache_time= 50-5 = 45
最后会使用 max-age 作为 缓存时间,因为最短
第二种设置
max-age=100,那么 cache_time= 100
max-stale=5,那么 cache_time= 50+5 = 55
max-fresh=2,那么 cache_time= 50-5 = 45
最后会使用 max-fresh 作为 缓存时间,因为最短
原来浏览器喜欢短的......
响应返回 Expires
设定一个具体的时间
Expires: Mon, 13 Aug 2018 03:40:08 GMT
Expires 时间到了之后,缓存就过期了
默认启发式缓存日期算法
当 没有设置,Cache-Control 和 Expires 的时候,就使用默认算法
取 响应头的 Date 减去 Last-Modified ,然后乘以 10% 作为缓存时间
var cacheTime = (new Date(date)-new Date(last-modified) )/10 var Expires_value = new Date(Date_value + cacheTime);
最后 Expires_value 就是缓存到期的时间
设置缓存
是否缓存
Pragma:no-cache 或者 Cache-Control:no-cache
设置缓存时间
Expires: Mon, 13 Aug 2018 03:40:08 GMT
Cache-Control: max-age=10.....(其他略)
禁用缓存
1、请求头设置
Cache-Control: no-cache, no-store, must-revalidate
2、资源设置版本号
reset_041c3208.css
3、页面 head 加入 meta
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate"/>