Skip to content
本页目录

浏览器缓存

接下来以三个部分来学习一下浏览器的缓存机制:

  • 强缓存
  • 协商缓存
  • 缓存的位置

1、强缓存

  • 强缓存不需要发送 HTTP 请求。

  • 是否强缓存由 ExpiresCache-ControlPragma 3 个 Header 属性共同来控制。


HTTP/1.0时期,是否强缓存使用的是Expires,而HTTP/1.1使用的是Cache-Control。让我们首先来看看Expires

Expires

  • Expires 即过期时间,存在于服务器返回的响应头中,其用于告诉浏览器在某个时间之前可以直接从缓存里面获取数据,不需要再次向服务器发送请求。
  • Expires 的优先级在三个 Header 属性中是最低的。

缺点

Expires 这个属性来控制是否使用强缓存有一个坑,就是有时候服务器的时间和浏览器的时间可能并不一致。导致服务器返回的这个过期时间不准确。所以 Expires 很快在后来的 HTTP1.1 版本中被抛弃了。

Cache-Control

  • Cache-ControlHTTP/1.1 中新增的属性。

  • 在请求头和响应头中都可以使用,它和 Expires 本质的不同在于它并没有采用具体的过期时间点这个方式,而是采用过期时长来控制缓存,对应的字段是max-age

js
Cache-Control:max-age=600

上面代码代表服务器返回响应之后 10 分钟内可以直接使用缓存。

其他 Cache-Control 常用属性如下:

  • public:响应可以被中间代理、CDN 等缓存。

  • private:专用于个人的缓存,中间代理、CDN 等不能缓存此响应。

  • must-revalidate:在缓存过期前可以使用,过期后必须向服务器验证

  • no-store:禁止使用缓存。

  • no-cache: 跳过当前的强缓存,发送 HTTP 请求,即直接进入协商缓存阶段。

当 Expires 和 Cache-Control 同时存在的时候, Cache-Control 会优先考虑。

Pragma

  • Pragma 是一个在 HTTP/1.0 中规定的通用首部,这个首部的效果依赖于不同的实现,所以在“请求-响应”链中可能会有不同的效果。它用来向后兼容只支持 HTTP/1.0 协议的缓存服务器,那时候 HTTP/1.1 协议中的 Cache-Control 还没有出来。

  • Pragma 只有一个属性值,就是 no-cache ,效果和 Cache-Control 中的 no-cache 一致,不使用强缓存,需要与服务器验证缓存是否新鲜。

注意

由于 PragmaHTTP 响应中的行为没有确切规范,所以不能可靠替代 HTTP/1.1 中通用首部 Cache-Control,尽管在请求中,假如 Cache-Control 不存在的话,它的行为与 Cache-Control: no-cache 一致。建议只在需要兼容 HTTP/1.0 客户端的场合下应用 Pragma 首部。

2、协商缓存

当浏览器的强缓存失效,或者请求头中设置了不走强缓存的时候。浏览器在请求头中携带 If-Modified-SinceIf-None-Match 这两个属性来向服务器发请求,由服务器根据这两个属性来决定是否使用缓存,这就是协商缓存。

Last-Modified

  • Last-Modified 即最后修改时间,在浏览器第一次给服务器发送请求后,服务器会在响应头中加上这个字段,值为服务器返回数据的最后修改时间。

  • 浏览器接收到后,如果再次发起同一个请求,会在请求头中携带If-Modified-Since 这个字段,这个字段的值也就是服务器传来的最后修改时间。

  • 服务器拿到请求头中 If-Modified-Since 字段后,就拿它的值与服务器中该资源的最后修改时间相比一下。

  • 如果请求头中的这个值小于最后修改时间,说明资源已经更新了。需要返回新的资源,跟常规的 HTTP 请求响应的流程一样。

  • 否则说明资源没有发生改变,直接返回 304,告诉浏览器使用缓存。

ETag(资源唯一标识)

  • ETag 是服务器根据当前文件的内容,给文件生成的唯一标识,只要里面的内容有改动,这个值就会改变。在浏览器第一次给服务器发送请求后,服务器会通过响应头把这个值(请求资源的 ETag)给浏览器。

  • 浏览器接收到 ETag 的值后,会在下次请求时将这个值作为If-None-Match 这个属性的值放到请求头中,然后发给服务器。

  • 服务器接收到 If-None-Match 后,会跟服务器上该资源的 ETag 进行对比。

  • 如果两者不一样,说明要更新了。返回新的资源,跟常规的 HTTP 请求响应的流程一样。

  • 否则说明资源没有发生改变,直接返回 304,告诉浏览器使用缓存。

Last-Modified VS ETag(资源唯一标识)

在精准度上,ETag 优于 Last-Modified。因为 ETag 是按照内容给资源生成唯一标识,因此能准确感知资源的变化。而 Last-Modified 就不一样了,它在一些特殊的情况并不能准确感知资源变化,主要有两种情况:

  • 1、如果文件的Last-Modified/If-Modified-Since 会错误地返回 304

  • 2、的时候,Last-Modified/If-Modified-Since 也会错误地返回 304

在性能上,Last-Modified 优于 ETag,也很简单理解,Last-Modified 仅仅只是记录一个时间点,而 Etag 需要根据文件的具体内容生成哈希值。

MIT Licensed