http - 缓存

63 阅读4分钟

1. http缓存

http缓存分为两种:

  • 强制缓存
  • 协商缓存

缓存作为http优化的手段,主要是通过将相应内容存储到本地,以减少http请求的发生。

简单而言,客户端在第一次请求某个url时,将响应内容存储至本地,再下一次请求同样的url时,直接从本地获取响应内容。同时,这也带来一个问题,万一缓存的内容并不是最新的,客户端并不知情,这种情况如何处理,这也缓存策略发挥作用的地方。

1.1 强制缓存

强制缓存下,响应会指定此次响应内容的过期时间,而浏览器在下次请求时会判断缓存是否过期,未过期则直接使用缓存内容。

涉及两个HTTP响应头字段:

  • Cache-Control 相对时间,优先级更高
  • Expires 是设置过期时间(绝对时间),但是如果用户的本地时间错乱了,可能会有问题

在有效期内请求会使用缓存,在有效期外会向服务器重新请求内容,并根据响应头内容更新对应字段。

1.2 协商缓存

协商缓存下,浏览器是否使用缓存内容,需要多一步与服务端协商的过程。 服务端协商通过后,会使用响应码304告诉浏览器可以使用本地资源(与服务端协商之后,通过协商结果来判断是否使用本地缓存。)

两种实现:

  • 第一种 基于时间
    • 响应头部使用 Last-Modified,标识该资源最后的修改时间
    • 请求头部使用 If-Modified-Since,询问在此时间之后该资源是否有修改,服务端将该值与本地文件的修改时间做比较,
      • 如果相同,则相应304
      • 否则200返回资源
    • 问题:时间篡改
  • 第二种 基于标识
    • 响应头部使用ETag,表示该资源的唯一标识
    • 请求头部使用If-None-Match,通过对比浏览器和服务器资源的特征值(如MD5)来决定是否要发送文件内容,
      • 如果一样就只发送 304(not modified)
      • 否则200返回资源
    • 可准确判断文件内容是否被修改

Etag的优先级比Last-Modified高:

  • 没有修改内容,但修改了时间的情况
  • 时间粒度问题:文件在1秒内多次修改
  • 有些服务器不能精确获取文件的最后修改时间。

1.3 两种缓存关系

协商缓存这两个字段都需要配合强制缓存中 Cache-Control 字段来使用,只有在未能命中强制缓存的时候,才能发起带有协商缓存字段的请求

优先使用强制缓存,再使用协商缓存,而在协商缓存中,优先使用ETag,再使用Last-Modified。

完整流程如下:

1.4 Cache-Control相关字段

1.4.1 max-age

先了解一下前面讲的Expires用的是绝对事件,具体如下:

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

而Cache-Control中使用max-age表示存储的有效期,是个相对时间,单位为秒,如下所示用600表示6分钟

Cache-Control: max-age=600

1.4.2 public / private

响应传输过程中会经过大量代理服务器,可以使用publicprivate控制代理服务器的缓存行为

  • public:公共缓存,任意方可缓存
  • private:私有缓存,仅接收方缓存,代理服务器不可缓存

其中public情况下可为代理服务器的资源设置过期时间:

Cache-Control: s-maxage=604800

1.4.3 no-cache / no-store

Cache-Control: no-cache

no-cache用于防止从缓存中返回过期的资源

image.png no-cache并不是表示不可缓存,而是每次使用资源时都要进行一次协商缓存,查询缓存是否有效

no-cache 相当于禁掉了强缓存,每次都要协商下

Cache-Control: no-store

no-store是真正地不允许缓存

1.4.4 must-revalidate

must-revalidate表示一旦资源过期,在成功向原始服务器验证之前,不能使用。

一般情况下,用户并不会使用过期的资源,但一些CDN厂商会使用过期资源,这个时候设置must-revalidate可以禁止这类情况的发生。

Cache-Control: max-age=0; must-revalidate;

分析以上指令,到期时间为0,即该资源立马过期,而设置了must-revalidate表示过期了的资源不可用,需要验证,所以必定会发起验证。

要使用必须先发起验证,其实以上等价于

Cache-Control: no-cache