http缓存梳理-强制缓存与协商缓存

http缓存策略有很多,ETag,Cache-Control,ETag,Last-Modified各有各的场景和用处。我们来梳理梳理...

# 缓存的作用

缓存的目的就是减少计算,算过一次的结果存下来下次直接用,本质上还是一种空间换时间的策略。

http缓存策略也是同理,为了避免重复请求相同的资源,浪费带宽,浪费请求,最重要的浪费时间,会让最终的页面呈现时间变长。用户体验下降。 页面打开白屏过长是不可接受的。缓存可以很好的解决这些问题点。

然而缓存虽好,随之而来的副作用也很明显。那就是资源要更新怎么办。这也是为什么会有如此多缓存策略的由来,针对不同的更新方式,http缓存策略提供 了多种多样的使用场景。

# 强制缓存与协商缓存

强制缓存不用发请求直接用本地缓存,协商缓存要发请求去问服务器有没有更新。

类型 关键字
强制缓存 ExpiresCache-Control
协商缓存 ETagLast-Modified

# 强制缓存-Cache-Control

通用消息头字段,被用于在http请求和响应中,通过指定指令来实现缓存机制。缓存指令是单向的,这意味着在请求中设置的指令,不一定被包含在响应中。

Cache-Control可设置属性也比较多,max-age只是其中一个属性,长这样:

Cache-Control: max-age=20000

表示当前资源在20000秒内都不用再请求了,直接使用缓存。

no-cache:使用缓存前,强制要求把请求提交给服务器进行验证(协商缓存验证)。

no-store:不存储有关客户端请求或服务器响应的任何内容,即不使用任何缓存。

# 强制缓存-Expires

服务器response的header带上这个字段

Expires: Wed, 21 Oct 2000 07:28:00 GMT

表示在这个时间前,客户端浏览器都不会再发起请求,而是直接用缓存资源。

如果在Cache-Control响应头设置了 "max-age" 或者 "s-max-age" 指令,那么 Expires 头会被忽略。

# 协商缓存-ETag

ETagHTTP响应头是资源的特定版本的标识符。这可以让缓存更高效,并节省带宽,因为如果内容没有改变,Web服务器不需要发送完整的响应。 而如果内容发生了变化,使用ETag有助于防止资源的同时更新相互覆盖.

他类似于文件的md5,计算方式也类似,当服务器返回时,可以根据返回内容计算一个hash值或者就是一个数字版本号, 具体返回什么值要看服务器的计算策略。然后将它加到response的header里面,可能长这样

etag: "19733-PoRqBqNvJFVYfvo+YLThhVrefts"

如果用户再次访问给定的URL(设有ETag字段),显示资源过期了且不可用,客户端就发送值为ETag的If-None-Match header字段

If-None-Match: "33a64df551425fcc55e4d42a148795d9f25f89d4"

服务端拿到请求里面的If-None-Match跟当前版本的ETag比较下:

  1. 如果是一样的话,直接返回304,语义为Not Modified,不返回内容(body),只返回header,告诉浏览器直接用缓存。
  2. 如果不一样的话,返回200和最新的内容

# 协商缓存-Last-Modified

服务器认定的资源做出修改的日期及时间。 它通常被用作一个验证器来判断接收到的或者存储的资源是否彼此一致。由于精确度比ETag要低(只能到秒),所以这是一个备用机制。

类似于ETag和If-None-Match的关系。只不过ETag放的是一个版本号或者hash值,Last-Modified放的是资源的最后修改时间。 Last-Modified是放到response的header里面的,可能长这样:

Last-Modified: Wed, 21 Oct 2020 07:28:00 GMT

客户端浏览器在使用时,应该将配套的If-Modified-Since放到request的header里面,长这样:

If-Modified-Since: Wed, 21 Oct 2020 07:28:00 GMT

服务端拿到这个头后,会跟当前版本的修改时间进行比较:

  1. 当前版本的修改时间比这个晚,也就是这个时间后又改过了,返回200和新的内容
  2. 当前版本的修改时间和这个一样,也就是没有更新,返回304,不返回内容,只返回头,客户端直接使用缓存

# ETag和Last-Modified优先级

ETag和Last-Modified都是协商缓存,都需要服务器进行计算和比较,那如果这两个都存在,用哪个呢? 答案是ETag,ETag的优先级比Last-Modified高。因为Last-Modified在设计上有个问题,那就是Last-Modified的精度只能到秒,如果一个资源频繁修改,在同一秒进行多次修改,你从Last-Modified上是看不出来区别的。 但是ETag每次修改都会生成新的,所以他比Last-Modified精度高,更准确。 但是ETag也不是完全没问题的,你的ETag如果设计为一个hash值,每次请求都要计算这个值,需要额外耗费服务器资源。 具体使用哪一个,需要根据自己的项目情况来进行取舍。

# 相关资料

ETag MDN文档:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/ETag (opens new window)

Last-Modified MDN文档:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Last-Modified (opens new window)

Expires MDN文档:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Expires (opens new window)

Cache-Control MDN文档:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Cache-Control (opens new window)

最近更新
01
echarts扇形模拟镜头焦距与可视化角度示意图
03-10
02
vite插件钩子
03-02
03
vite的依赖预构建
02-13
更多文章>