FED

©FrontEndDev.org
2015 - 2024
web@2.23.0 api@2.21.1

Http 协议基础知识2:缓存

缓存

首先缓存有很多种,这里大致介绍下和前端有关的缓存,着重说下http协议相关的缓存。

  1. client在发起一个http请求前,可能先会检查下是否已经请求过这个uri,如果是并且缓存有效的话,就不用发请求了,直接读取本地缓存即可。这一步的缓存是http协议层面的缓存。
  2. 当已经请求过的uri在此被较为强制的理由请求时(如用户主动刷新页面),那么client就不能完全使用本地缓存了,它会发起一个带有缓存协商的http请求,和server商量好本地缓存可用的话,server会返回304,并且无响应体,client加载本地缓存,否则server返回200,并返回响应体。
  3. 请求在到达server前(这里的server指的是部署代码的server),可能会先到达cdn,cdn的原理是遍布各地的cdn节点在一次接到一个uri请求时,向中控机发起请求,获得该请求的文件,返回给用户并缓存下来。下次同样的请求就直接返回给用户了。这里的cdn缓存,不同的cdn实现不一样,有些是缓存文件名,有些是缓存url。所以前端开发人员在使用cdn的时候就需要了解其中是如何进行缓存的,你再中控机上更新一个文件,cdn节点是否会重新获得该文件。操作不当就会导致更新的内容在用户那里无法生效,因为cdn一直使用的旧的缓存文件。
  4. 请求穿过历尽万难到达你部署代码的server之后,在server端还会进行若干缓存,这里就不过多探讨了。与前端关系不大,是后端人员需要关注的。

机制

接下来详细解释下http的缓存机制。

http 主要是通过时间和内容两种办法来处理缓存的。

首先,client发起一个http请求之后,server会在http响应头里面告诉client,这个请求能否被缓存。这里有两个响应头可以用来做这件事儿。

Expires

一个是 Expires,表示请求的过期时间,是个绝对的时间,如Thu, 04 Jul 2013 06:25:39 GMT,client就知道,该请求在Expires的时间之前都是可用的,超过这个时间就不可用了。若强制请求不缓存,就设置个已经过去的时间即可。用Expires的缺点就是,这是个绝对的时间,而所有的server和client在绝对时间上,都是有一定误差的。

Cache-Control

另一个是Cache-Control,常用的就是max-age,表示缓存的有效时间,单位为毫秒。如:Cache-Control:max-age=14400。在请求该uri之后的max-age之内,认为改请求的缓存是有效的。若强制请求不缓存,可以设置为0。

理论上,ExpiresCache-Control只用其一即可,两个都用是非法的。这样便解释了上面提到的第1中缓存的情况。即强缓存,在浏览器中,一般除非用户刷新等主动强制更新缓存的操作,都会采用上面的方法处理缓存。

client已经缓存了某个uri之后,还是需要访问服务器的时候,client和server就要进行缓存协商了。常用的缓存协商有两种方法,一种是最后修改日期,另一种是版本号。

Last-Modified

先说下最后修改日期。请求的响应头中,server可能会写入Last-Modified字段,表示改请求最后一次修改的时间。client第二次发送这个请求时,就会带上If-Modified-Since的请求头,告诉server,只有请求内容在某个时段之后修改过,才返回给我。server中看到这个请求头,会验证在某个时段后是否修改过。若修改过,返回200,并返回最新的请求体,否则返回304,告诉client,请使用你的本地缓存吧。

ETag

最后修改日期验证,应该很容易理解,下面说下版本验证,也就是ETag。

首先,client是不会理解ETag是怎么生成的,它只负责记录ETag,并告诉server。至于server中如何计算ETag,也没有规定。只要你遵守一个原则即可:内容不变,ETag不变,内容变化,ETag变化。到底你用md5还是什么算法,那就看具体情况了。

请求的响应头中,server会将计算好的ETag返回给client。client下次请求时,会带上If-None-Match的请求头,告诉server,只有ETag不匹配的时候,你才返回给我内容,否则我就使用缓存。server端的处理同Last-Modified时。

如果同时存在ETag和Last-Modify验证怎么办呢?server会同时验证两个,都满足时才返回304,有一个不满足就要返回200,给client最新的内容。