跳至主要內容

HTTP 缓存

njr计算机网络HTTP大约 4 分钟约 1136 字

对于一些相同的请求,通过复用以前获取的资源,显著提高网页的性能。Web 缓存减少了等待时间和流量,因此减少了显示资源的渲染时间。

HTTP 缓存的实现有两种方式,分别是强制缓存协商缓存

强缓存

强缓存是指:只要浏览器判断缓存没有过期,则直接使用本地缓存,不会向服务器发送请求。

强缓存是利用下面这两个字段实现的,它们都用来表示资源在客户端缓存的有效期。

  • Expires:绝对时间;
  • Cache-Control:缓存指令。

Expires

响应头包含的日期时间,在这个时间前,浏览器都不会再发起请求,而是直接使用缓存资源。

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

Cache-Control

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

Cache-Control: max-age=20000

max-age=<seconds> 可以设置过期时间(单位秒),相对于请求的时间计算。

具体流程:

  1. 当浏览器第一次向服务器发起请求时,服务器响应头会带上 Cache-Control,其中设置了过期时间 max-age
  2. 浏览器再次向服务器发起请求后,会计算当前请求时间和过期时间差值,来判断是否过期,如果过期则重新请求服务器,否则使用本地缓存;
  3. 如果已经过期,服务器再次收到请求后,会更新响应头的 Cache-Control

除了 max-age 外,还有其他指令,详见 Cache-Controlopen in new window

优先级

当同时有 ExpiresCache-Control 字段时,如果 Cache-Control 响应头设置了 max-ages-maxage 指令,那么 Expires 会被忽略。

协商缓存

为了知道服务器有没有更新内容,必须和服务器沟通,然后根据服务器返回的信息判断是否使用本地缓存,这种方式称为协商缓存

协商缓存通过两种头部实现:

  • 请求头部的 If-Modified-Since 和响应头部的 Last-Modified
  • 请求头部的 If-None-Match 和响应头部的 ETag

If-Modified-SinceLast-Modified

这种方式是基于时间实现的。

响应头 Last-Modified 存放的是资源最后修改时间:

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

请求头中的 If-Modified-Since 含义为资源从 xxx 时间后是否有更新:

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

当服务器收到浏览器这个请求头后,会跟当前版本的时间进行比较:

  1. 当前版本的修改时间比这个晚,也就是内容发生变化了,那么会返回 200 和新的内容;
  2. 若当前版本的修改时间较早,也就是没有更新,那么会返回 304,浏览器会从缓存中读取内容。

ETagIf-None-Match

这种方式是通过唯一标识实现。

ETag 是资源的特定版本的标识符,响应头会根据返回内容返回一个标识符,具体返回值看服务器的计算策略,可能如下所示:

ETag: '33a64df551425fcc55e4d42a148795d9f25f89d4'

当客户端收到这个响应后,会将这个 ETag 保存起来,等下个请求时,会将它放到请求体的 If-None-Match 字段中:

If-None-Match: "33a64df551425fcc55e4d42a148795d9f25f89d4"

当服务器收到浏览器这个请求头后,会跟当前版本的 ETag 进行比较:

  1. 如果标识符不一致,也就是内容发生变化了,那么会返回 200 和新的内容;
  2. 如果标识符一致,也就是没有更新,那么会返回 304,浏览器会从缓存中读取内容。

优先级

协商缓存先检查上一次响应头中是否有 ETag,如果有,则发起请求中请求头带上 If-None-Match 字段;如果没有,则检查上一次响应头中是否有 Last-Modified 字段,发起请求中请求头带上 If-Modified-Since 字段。

总结

HTTP 缓存机制分为两种:强缓存和协商缓存。

浏览器会首先判断强缓存,如果强缓存生效,那么直接从缓存中获取资源;若没有生效,则会使用协商缓存,发送请求与服务器协商。