通过网络提取内容既速度缓慢又开销巨大。 较大的响应需要在客户端与服务器之间进行多次往返通信,这会延迟浏览器获得和处理内容的时间,还会增加访问者的流量费用。 因此,缓存并重复利用之前获取的资源的能力成为性能优化的一个关键方面
昨天正好面试到了,所以也是对自己知识的一个补充吧,下面就对http缓存进行介绍。
所谓缓存,可以理解为中间的存储。在请求资源的时候,不通过网络,而是直接使用磁盘或者内存中已经在上一次请求中所下载到的资源,这样就避免了网络传输的延迟,优化了页面加载速度。
在了解Http的缓存机制之前,先来看看http中有哪些缓存
http缓存中有两种缓存
- 强制缓存
- 协商缓存
## 强制缓存
客户端直接通过缓存中获取数据,不会于服务端发生交互
对于强制缓存,服务器响应中有两个字段
Expires
Cache-Control
Expires
它是http/1.0中的缓存机制,它描述的是一个绝对的时间。当第一次请求资源时,响应体会包含Expires字段。
1 | Expires: Tue, 22 Oct 2019 07:58:14 GMT |
如果当前请求的时间大于Expires字段的时间,那么说明强制缓存已经过期。
Expires 字段的这种方式有一个明显的缺点,由于失效时间是一个绝对时间,所以当客户端本地时间被修改以后(修改系统的时间),就有可能导致缓存混乱。于是发展出了Cache-Control
Cache-Control
指令不区分大小写,并且具有可选参数,可以用令牌或者带引号的字符串语法。多个指令以逗号分隔。
常见取值public、private、no-cache、max-age、no-store,默认为private
private
:响应只能被单个用户缓存,不能作为共享缓存(代理服务器不能缓存)public
:可以被任何对象缓存(包含发送请求的客户端,代理服务器 )no-cache
:这里的no-cache不是表示不使用缓存,表示先把缓存提交给服务器验证( 后面的协商缓存)no-store
: 表示不适用缓存,直接发送请求max-age
:设置缓存的生存周期,(单位秒)
比如,当Cache-Control中指定了max-age=600
1 | Date: Tue, 22 Oct 2019 09:27:42 GMT |
表示该缓存在10分钟后过期,配合响应中的Date,就能得出缓存过期的时间
协商缓存(有的也称对比缓存)
当强制缓存过期后,使用协商缓存,这时会发送一些字段给服务器验证,查看缓存是否过期
如果没有过期则返回状态码304,之后直接使用缓存作为响应体。
如果已经过期,则重新通过网络传输文件
协商缓存一般有下面的两种
- Last-Modified/If-Modified-Since
- Etag/If-None-Match
Last-Modified/If-Modified-Since
- 服务器响应请求时,头部会加上Last-Modified,表示该资源的最后修改时间
1 | Last-Modified: Fri, 18 Oct 2019 05:43:24 GMT |
- 之后的客户端发起的每次请求都在If-Modified-Since设置为该值
1 | If-Modified-Since: Fri, 18 Oct 2019 05:43:24 GMT |
这样服务端通过对比If-Modified-Since和资源最后的修改时间判断是否命中缓存
Last-Modified虽然已经足够好,但是Last-Modified只能精确到秒,如果某些文件在1秒内被修改多次,它将不能准确标注文件被修改的具体时间。
有些相同的文件会定时生成,他们的Last-Modified不同,导致没法使用缓存
所以又有了下面的Etag
Etag/If-None-Match
与上面不同的是,该方法通过一个标识符来确定是否命中缓存
- 服务器响应请求时,头部会加上Etag(Entity Tag),它是该资源的唯一标识,Etag的值改变了说明资源已经更新
1 | Etag: W/"5da950fc-3be" |
- 客户端发送请求时,在If-None-Match字段加上Etag的值
1 | If-None-Match: W/"5da950fc-3be" |
服务端将收到的If-None-Match字段与Etag对比,如果相同则命中缓存
http缓存机制
通常情况下,http缓存会以如下方式工作
浏览器第一次请求
第一次请求时,发现无缓存,则直接向web服务器请求,web服务器返回响应,并缓存。如果设置了Cache-Control: no-store之类的则不会缓存文件。
再次请求
再次请求时:
- 查看缓存的中响应的Cache-Control或Expires字段,如果两者同时存在,则查看Cache-Control
- 若资源过期,比如Cache-Control的max-age=10,你在10秒后发送了这个请求,此时资源已经过期,则检查是否带有Etag
- 若带有Etag,将这个Etag的值作为请求If-None-Match字段的值,发送给服务器验证,返回304或者200
- 若没有Etag,检查是否有Last-Modified
- 若有Last-Modified,将这个Last-Modified的值作为请求If-Modified-Since的值,发给服务器验证,返回304或者200
- 若没有Last-Modified,则直接向web服务器请求资源