前导
浏览器的缓存过程
- 开始加载、域名解析、DNS解析
- 本地缓存(memory cache):不受开发者和HTTP协议控制,关闭页面即消失
- http缓存:分为强缓存和协商缓存,强缓存失效之后使用协商缓存
- 服务器缓存:都失效,则向服务器重新请求资源
客户端每次请求后根据会根据服务器响应的HTTP头部的缓存标识进行缓存。
每次HTTP请求前都会先给浏览器请求发送缓存
每次HTTP请求后,都会根据缓存标识符将结果写入浏览器缓存
memory cache(本地缓存)
几乎所有的网络请求资源都会根据相关的策略被浏览器自动加入到 memory cache 中。但是也正因为数量很大但是浏览器占用的内存不能无限扩大这样两个因素,memory cache 注定是个短期存储,不可能无限扩展。但是这种存储策略也保证了,若一个页面发起两个相同的请求,那么只会进行一次,比如相同的图片之类的,大大降低了请求数量。若 memory cache失效,那么就会查看HTTP缓存。
浏览器缓存
强缓存
控制字段:Expires(优先级低)&Cache-Control(优先级高),设置两个字段是为了兼容不同的浏览器,因为有些浏览器Cache-Control无效。
Expires:
服务器响应消息头,指明了资源到期时间,需要和Last-modified一起使用。告知服务器在Expires到期之前可以直接从浏览器中获取资源。(如果修改了本地时间,可能造成缓存失败)
Cache-Control:
-public 客户端和代理服务器都可以缓存
-private 只有客户端可以缓存
-no-cache 客户端缓存内容,但是是否缓存则根据协商缓存决定
-no-sore 所有的内动都不缓存,既不强缓存,也不协商缓存
-max-age=xxx 缓存将在xxx秒之后失效
…
例:当服务器希望客户端缓存响应的资源的时候,就会在响应头加入以下字段:
Cache-Control: max-age=3600 //强缓存3600s
Expires: Thu, 10 Nov 2020 08:45:11 GMT //过期时间
Date: Thu, 30 Apr 2020 12:39:56 GMT
Etag:W/"121-171ca289ebf"//资源编号
Last-Modified:Thu, 30 Apr 2020 08:16:31 GMT
补充:为什么现在更倾向于使用Cache-Control而不是Expries——Expries更依赖本地时间,当浏览器和服务器时间不一致的时候,会出错。
协商缓存
控制字段:Last-Modified(优先级低)&Etag(优先级高),因为Last-Modified的精度低,不敏感,无法检测到1秒之内文件的修改,而且文件可能定时刷新,但内容并未修改。
如果浏览器发现强缓存的资源已经过期,那该怎么办呢,这时候浏览器会发送给服务器一个请求,问:这个资源已经过期,那还能继续使用吗~?服务器就会查询这个资源是否已经被修改,如果未修改,那么会回复:304——是的!还能使用,并且带上新的缓存策略;若已经被修改,那么服务器会像回应一个新的资源申请请求一样:200——带上响应体和缓存指令。
那么服务器通过什么标准来判断资源是否被修改呢?
Last-Modified
第一次响应浏览器请求时,服务器会带上Last-Modified字段,当浏览器再次请求该资源时,会带上一个ifmodifiedsince字段,带上这个时间,服务器对比这个时间是否和服务器的上次修改时间一致。
但是,Last-Modified无法识别资源编辑过但内容未改变的情况,也无法识别毫秒内的修改(时间戳的单位是秒)所以就需要——Etag。
Etag
不同资源哈希计算之后的字符串,类似文件指纹。浏览器发起资源请求的时候,带上一个ifNoneMatch字段,服务器将对比浏览器资源和服务器资源的hash。
但是,如果资源比较大或修改比较频繁,那么生成hash的过程将会给服务器带来负担。
补充:
Etag字段值的生成分为强验证和弱验证,强验证根据资源内容进行生成,能够保证每个字节都相同,弱验证则根据资源的部分属性来生成,生成速度快但无法确保每个字节都相同,并且在服务器集群场景下,也会因为准确不够而降低协商缓存有效性的成功率,所以恰当的方式是根据具体的资源使用场景选择恰当的缓存校验方式。
实现缓存的方法(待补充)
用标签修改服务器响应html的响应头
<meta http-equiv="Cache-Control" content="max-age=7200" />
后端响应请求时配置请求头,原理同上
略
修改nginx配置文件(优先级比2高,因为nginx是反向代理,服务器的响应先发给nginx再返回给客户端)
location ~* .(woff)$ {
proxy_pass http://kubernetes;
expires 1d;
}
参考: