# http 缓存策略,有什么区别,分别解决了什么问题
# 往期回顾
# react16 有哪些新特性,放弃了哪些生命周期
废弃的生命周期
- componantWillMount
- componantWillReceiveProps
- componantWillUpdate 新增
- 生命周期 componantDidCatch
- React.Profiler 监控
- hook 组件
- timeSpling 时间切片
- suspanse 网络 io
# 今日解题
# 1) 浏览器缓存策略
浏览器每次发起请求时,先在本地缓存中查找结果以及缓存标识,根据缓存标识来判断是否使用本地缓存,如果缓存有效,则使用本地缓存,否则,则向服务器发起请求并携带缓存标识,根据是否需要服务器发起 HTTP 请求,将缓存过程划分为两个部分:强制缓存和协商缓存,强缓优于协商缓存。
- 强缓存,服务器通知浏览器一个缓存时间,在缓存时间内,下次请求,直接用缓存,不在时间内,执行比较缓存策略
- 协商缓存,让客户端与服务器之间能实现缓存 文件是否更新的验证、提升缓存的复用率,将缓存信息中的 Etag 和 Last-Modified 通过请求发送给服务器,由服务器校验,返回 304 状态时,浏览器直接使用缓存 HTTP 缓存都是从第二次请求开始的:
- 第一次请求资源时,服务器返回资源,并在 Reponse Header 中会传资源的缓存策略
- 第二次请求时,浏览器判断这些请求参数,击中强缓存就直接 200,否则就把请求参数加到 request header 头中传给服务器,看是否击中协商缓存,击中则返回 304,否则服务器会返回新的资源。这是缓存运作的一个整体流程图:
|----------------------------------------------------浏览器缓存 缓存协商
| | |
| 状态是否是304 --200-->请求响应完成
| |
| 发起请求 ,请求头带上If-None-Match 发起请求 ,请求头带上If-Modified-Since
| | 是 | 是
开始 -> 浏览器 -> 发起GET请求 -> 是否有缓存 -> 上一次响应头中是否有ETag -> 上一次响应头中是否有Last-Modified
| | 是
读取浏览器缓存 <- 强制缓存是否新鲜
# 2) 强缓存
- 强缓存命中则直接读取浏览器本地的资源,在 network 中显示的是
from memory
或from disk
- 控制强制缓存的字段有:Cache-Control(http1.1)和 Expires(http1.0)
- Cache-control 是一个相对时间,用以表达在这个时间点之前发起请求可以直接从浏览器中读取数据,而无需发起请求
- Expires 是一个绝对时间,用以表达在这个时间点之前发起请求可以直接从浏览器中读取数据,而无需发起请求
- Cache-Control 的优先级比 Expires 的优先级高,前者的出现是为了解决 Expires 在浏览器时间被手动更改导致缓存判断错误的问题
- 如果同时存在则使用 Cache-Control
# 3) 强缓存-expires
- 该字段是服务器响应消息头字段,告诉浏览器在过期时间之前可以从浏览器缓存中存取数据
- Expires 是 HTTP1.0 的字段,表示缓存到期时间,是一个绝对时间(当前时间+缓存时间)。在响应消息头中,设置这个字段之后,就可以告诉浏览器,在未过期之前不需要再次请求
- 由于是绝对时间,用户可能会将客户端的时间进行更改,而导致浏览器判断缓存失效,重新请求该资源。此外,即使不考虑修改,时差或者误差等因素也可能造成客户端和服务端的时间不一致而导致缓存失效
- 优点
- HTTP1.0 产物,可以在 HTTP1.0 和 1.1 中使用,简单易用
- 以时刻标识失效时间
- 劣势
- 时间是服务器发送的 UTC 时间,如果服务器时间和客户端时间不一致,会出现问题
- 存在版本问题,到期之前的修改客户端是不可知的
# 4) 强缓存-cache-control
- 该字段表示资源缓存的最大有效时间,在该时间内,客户端不需要向服务器发送请求
- Cache-Control 常用的值
max-age
: 即最大有效时间must-revalidate
: 如果超过max-age
的时间,浏览器必须向服务器 发送请求,验证资源是否还有效no-cache
: 不使用强制缓存,需要与服务器验证缓存是否新鲜no-store
: 真正意义上的不要缓存
。所有内容都不走缓存,包括强制和对比public
: 所有的内容都可以被缓存(包括客户端和代理服务器,如 CDN)private
: 默认值,所有内容只有客户端才可以缓存,代理服务器不能缓存
- Cache-Control 优先级高于 Expires
- 该字段可以在请求头或响应头设置,可组合使用多种指令
- 可缓存性:
- public: 浏览器和缓存服务器都可以缓存页面信息
- private: default, 代理服务器不可缓存,只能被单个用户缓存
- no-cache: 浏览器和服务器都不应该缓存页面信息,但仍可以缓存,只是在缓存前需要向服务器确认资源是否被更改,可配合 private,过期时间设置为过去时间。
- only-if-cache: 客户端只接受已缓存的响应
- 到期
- max-age=: 缓存存储的最大周期,超过这个周期被认为过期
- s-maxage=: 设置共享缓存,比如 can, 会覆盖 max-age 和 expires
- max-stale[=]: 客户端愿意接收一个已过期的资源
- min-fresh=: 客户端希望在指定的时间内获取最新的响应
- stale-while-revalidate=: 客户端愿意接收陈旧的响应,并且在后台一部检查新的响应。时间代表客户端愿意接收陈旧响应的时间长度
- state-if-error=: 如新的检测失败,客户端则愿意接收陈旧的响应,时间代表等待 时间
- 重新验证和重新加载
- must-revalidate: 如页面过期,则去服务器进行获取
- proxy-revalidate: 用于共享缓存
- immutable: 响应正文不随时间改变
- 其他
- no-store: 绝对禁止缓存
- no-transform: 不得对资源进行转换和转变,比如不得对图像格式进行转换
- 可缓存性:
- 优势
- 以时间间隔标识失效时间,解决了 Expires 服务器和客户端相对时间的问题
- 有多个选项设置
- 劣势
- 存在版本问题,到期之前的修改客户端是不可知的
# 5) 协商缓存
- 协商缓存的状态码由服务器决策返回 200 或者 304
- 当浏览器的强制缓存失效的时候或者请求头中设置了不走强缓存,并且在请求头中设置了 If-Modified-Since 或 If-None-Match 的时候,会将这两个属性值到服务端验证是否命中协商缓存,如果命中就 304,加载浏览器缓存,并在响应头会设置 Last-Modified 或者 Etag 属性
- 对比缓存在请求数上和没有缓存是一致的,但如果是 304 的话,返回的仅仅是一个状态码而已,并没有实际内容 ,因此在响应体体积上节省是它的优化点
- 协商缓存有 2 组字段(不是两个),协商缓存的字段是:
Last-Modified/If-Modified-since(http1.0)
和Etag/if-none-match(http1.1)
- Last-Modified/If-Modified-since 表示的是服务器资源最后一次修改的时间;Etag/if-none-match 表示的是服务器资源的唯一标识,只要资源变化,Etag 就会重新生成
- Etag/If-None-match 的优先级比
Last-Modified/If-Modified-since
高
# 6) 协商缓存-Last-Modified/If-Modified-since
- 服务器通过
Last-Modified
字段告知客户端,资源最后一次被修改的时间,例如:Last-Modified: Mon,10 Nov 2018 09:10:11 GMT
- 浏览器将这个值和内容一起记录在缓存数据库中
- 下一次请求相同资源时,浏览器从自己的缓存中找出
不确定是否过期的缓存
。因此在请求头中将上次的 Last-Modified 的值写入到请求头 If-Modified-Since 字段 - 服务器会将 If-Modified-Since 的值与 Last-Modified 字段进行对比。如果相等,则表示未修改,响应 304;反之,则表示修改了,响应 200 状态码,并返回数据
- 优势:
- 不存在版本问题
- 劣势:
- 只要资源修改,无论内容是否发生实质性变化,都会将该资源返回客户端。例如:周期性重写,这种情况下该资源包含的数据实际上一样的
- 如果 1m 内多次变化,则不能识别到
- 某些服务器不能精确到文件的最后修改时间
- 如果文件是服务端生成的,则更新时间永远在变化,无法缓存
# 7) 协商缓存-Etag/If-None-match
- 为了解决 Last-Modified 问题,而新增了
Etag
和If-None-Match
- Etag 存储的是文件的特殊标识(一般都是 hash 生成的),服务器存储着文件的 Etag 字段。之后的流程和
Last-Modified
一致,只是 Last-Modified 字段和它所表示的更新时间更新时间改变成了 Etag 字段和它所表示的文件 hash,把 if-modified-since 变成 If-None-Match,服务器同样进行比较,命中返回 304,反之返回资源及 200 - If-None-Match 从浏览器里读 Etag,和服务端 Etag 对比
- 优势特点
- 1、可以更加精确的判断资源是否被修改,可以识别一秒内多次修改的情况。
- 2、不存在版本问题,每次请求都回去服务器进行校验。
- 劣势问题
- 1、计算 ETag 值需要性能损耗。
- 2、分布式服务器存储的情况下,计算 ETag 的算法如果不一样,会导致浏览器从一台服务器上获得页面内容后到另外一台服务器上进行验证时现 ETag 不匹配的情况。