HTTP 缓存
对于一些相同的请求,通过复用以前获取的资源,显著提高网页的性能。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>
可以设置过期时间(单位秒),相对于请求的时间计算。
具体流程:
- 当浏览器第一次向服务器发起请求时,服务器响应头会带上
Cache-Control
,其中设置了过期时间max-age
; - 浏览器再次向服务器发起请求后,会计算当前请求时间和过期时间差值,来判断是否过期,如果过期则重新请求服务器,否则使用本地缓存;
- 如果已经过期,服务器再次收到请求后,会更新响应头的
Cache-Control
。
除了 max-age
外,还有其他指令,详见 Cache-Control。
优先级
当同时有 Expires
和 Cache-Control
字段时,如果 Cache-Control
响应头设置了 max-age
或 s-maxage
指令,那么 Expires
会被忽略。
协商缓存
为了知道服务器有没有更新内容,必须和服务器沟通,然后根据服务器返回的信息判断是否使用本地缓存,这种方式称为协商缓存。
协商缓存通过两种头部实现:
- 请求头部的
If-Modified-Since
和响应头部的Last-Modified
; - 请求头部的
If-None-Match
和响应头部的ETag
。
If-Modified-Since
和 Last-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
当服务器收到浏览器这个请求头后,会跟当前版本的时间进行比较:
- 当前版本的修改时间比这个晚,也就是内容发生变化了,那么会返回 200 和新的内容;
- 若当前版本的修改时间较早,也就是没有更新,那么会返回 304,浏览器会从缓存中读取内容。
ETag
和 If-None-Match
这种方式是通过唯一标识实现。
ETag
是资源的特定版本的标识符,响应头会根据返回内容返回一个标识符,具体返回值看服务器的计算策略,可能如下所示:
ETag: '33a64df551425fcc55e4d42a148795d9f25f89d4'
当客户端收到这个响应后,会将这个 ETag
保存起来,等下个请求时,会将它放到请求体的 If-None-Match
字段中:
If-None-Match: "33a64df551425fcc55e4d42a148795d9f25f89d4"
当服务器收到浏览器这个请求头后,会跟当前版本的 ETag
进行比较:
- 如果标识符不一致,也就是内容发生变化了,那么会返回 200 和新的内容;
- 如果标识符一致,也就是没有更新,那么会返回 304,浏览器会从缓存中读取内容。
优先级
协商缓存先检查上一次响应头中是否有 ETag
,如果有,则发起请求中请求头带上 If-None-Match
字段;如果没有,则检查上一次响应头中是否有 Last-Modified
字段,发起请求中请求头带上 If-Modified-Since
字段。
总结
HTTP 缓存机制分为两种:强缓存和协商缓存。
浏览器会首先判断强缓存,如果强缓存生效,那么直接从缓存中获取资源;若没有生效,则会使用协商缓存,发送请求与服务器协商。