http缓存机制
https://juejin.cn/post/7052527032491573279
https://juejin.im/post/5bdeabbbe51d4505466cd741?utm_source=gold_browser_extension
https://www.cnblogs.com/yalong/p/9956185.html
1.缓存相关概念解释
缓存命中
如果某个请求的结果是由已缓存的副本提供的,被称作缓存命中。
缓存未命中
如果缓存中没有可用的副本或者副本已经过期,则会将请求转发至原始服务器,这被称作缓存未命中
新鲜度检测
HTTP通过缓存将服务器文档的副本保留一段时间。在这段时间里, 都认为文档是“新鲜的”,缓存可以在不联系服务器的情况下,直接提供该文档。但一旦已缓存副本停留的时间太长,超过了文档的新鲜度限值(freshness limit), 就认为对象“过时”了,在提供该文档之前,缓存要再次与服务器进行确认,以查看文档是否发生了变化。
再验证
原始服务器上的内容可能会随时变化,缓存需要经常对其进行检测,看看它保存的副本是否仍是服务器上最新的副本。这些新鲜度检测被称为 HTTP 再验证。
缓存可以随时对副本进行再验证,但大部分缓存只在客户端发起请求,并且副本旧得足以需要检测的时候,才会对副本进行再验证。
再验证命中和再验证未命中
- 缓存对缓存的副本进行再验证时,会向原始服务器发送一个再验证请求,如果内容没有发生变化,服务器会以304 Not Modified进行响应。这被称作是再验证命中或者缓慢命中。
- 如果内容发生了变化,服务器会以200进行响应。这被称作再验证未命中。
2. 缓存的处理步骤
- 首先是当用户请求资源时,会判断是否有缓存,如果没有,则会向原服务器请求资源。
- 如果有缓存,则会进入强缓存的范畴,判断缓存是否新鲜,新鲜——>直接返回缓存副本给客户端,不新鲜——>则强缓存失败,将会进入到协商缓存。
- 协商缓存将判断是否存在Etag和Last-Modified首部,通过这些首部验证资源是否发生过变化,如果未发生变化,则表示命中了协商缓存,会重定向到缓存副本,将资源返回给客户端,否则的话表示协商缓存未命中,服务器会返回新的资源。
3.强缓存:
不向服务器发送请求,强制使用缓存
实现方式:
后端在响应头中返回Expires和Cache-control
Expires 和 Cache-Control:max-age都是用来标识资源的过期时间的首部
Expires(http/1.0)
描述的是一个绝对时间,由服务器返回,用GMT格式的字符串表示,用来指定资源到期时间;
注意:由于expires是一个绝对时间,如果人为的更改时间,会对缓存的有效期造成影响,使缓存有效期的设置失去意义,因此在http1.1中我们有了expires的完全替代首部cache-control:
max-age
Cache-Control(http/1.1)
max-age值是一个相对时间,它定义了文档的最大使用期——从第一次生成文档到文档不再新鲜、无法使用为止,最大的合法生存时间(以秒为单位)。
过程说明
- 当我们首次请求资源时,服务器在返回资源的同时,会在Response Headers中写入expires首部或cache-control,标识缓存的过期时间,缓存副本会将该部分信息保存起来。
- 当再次请求该资源的时候,缓存会对date(Date是一个通用首部,表示原始服务器消息发出的时间。即表示的是首次请求某个资源的时间。)和expires/cache-control的时间进行对比,从而判断缓存副本是否足够新鲜。
4.协商缓存
实现方式
通过请求头Last-Modified或Etag来实现
Last-Modified 标识的是文档最后修改时间,Etag 则是以文档内容来进行编码的。
Last-Modified
- 首次请求资源时,服务器在返回资源的同时,会在Response Headers中写入Last-Modified首部,表示该资源在服务器上的最后修改时间。
- 当再次请求该资源时,会在Request Headers中写入If-Modified-Since首部,此时的If-Modified-Since的值是首次请求资源时所返回的Last-Modified的值。
- 服务器接收到请求后,会根据If-Modified-Since的值判断资源在该日期之后是否发生过变化。
- 没有变化——>返回304 Not Modified,变化——>1.返回变化过后的资源 + 2.同时更新Last-Modified的值。
Etag
Etag的实现过程和Last-Modified完全一样
Etag 强验证器和弱验证器
ETag 分为强验证器和弱验证器,强验证器要求文档的每个字节都相等,而弱验证器只要求文档的含义相等。
- 强验证:
- 弱验证(前面会加上‘ W/’ 来标识):
Last-Modified存在的一些问题
- 有些文档可能会被周期性地重写,但实际包含的数据常常是一样的。尽管内容没有变化,但修改日期会发生变化
- 有些文档可能被修改了,但所做修改并不重要,不需要让缓存重载数据(比如对拼写或注释的修改
- 有些服务器提供的文档会在亚秒间隙发生变化(比如,实时监视器),对这些服务器来说,以一秒为粒度的修改日期可能就不够用了。
无法感知文件内容是否真的发生了变化。 不该重新请求的时候,也会重新请求。
在秒以下的内容变化无法感知到。 该重新请求的时候,反而没有重新请求。
解決方法
针对上述问题,Etag作为Last-Modified的补充而出现,Etag 是由服务器为每个资源生成的唯一的标识字符串,这个标识字符串是基于文件内容编码的,只要文件内容不同,它们对应的 Etag 就是不同的,因此 Etag 能够精准地感知文件的变化。
5.Cache-Control请求头常用属性说明
max-age/s-maxage
s-maxage指令的功能和max-age是相同的,它们唯一的不同点就在于s-maxage指令只适用于代理服务器缓存。s-maxage的优先级高于max-age。
public/private
public 与 private 是针对资源是否能够被代理服务缓存而存在的一组对立概念。
如果我们为资源设置了 public,那么它既可以被浏览器缓存,也可以被代理服务器缓存;如果我们设置了 private,则该资源只能被浏览器缓存。
no-cache/no-store
no-cache 表示客户端要求缓存在提供其已缓存的副本之前必须先和原始服务器对该文档进行验证。即强制跳过强缓存阶段,直接进行协商缓存。强缓存并不能知道缓存是否真的足够新鲜,使用no-cache就是为了防止从缓存中返回过期的资源,对缓存进行再验证。
no-store表示的是禁止缓存,即每一次都是直接与原服务器进行通信,从原服务器返回资源。一般设置了no-store的资源,都暗示着该资源具有敏感性信息。
6.优先级问题
(1)Expires 和 Cache-Control: max-age
应用HTTP/1.1版本的缓存服务器遇到同时存在Expires首部字段的情况时,会优先处理max-age指令,而忽略掉Expires首部字段。 而HTTP/1.0版本的缓存服务器的情况则相反,max-age指令会被忽略掉。
(2)Last-Modified 和 Etag(存疑?)
很多资料都说Etag的优先级高于Last-Modified,但是又有资料说当Etag和Last-Modified同时存在时,是由二者共同决定标识文档是否发生变化的——?