1 概览

缓存 - 图1

一般来说浏览器缓存可以分为两类:

  • 强缓存
  • 协商缓存(对比缓存)

我们需要知道的是,浏览器在加载资源时,会先判断是否命中强缓存再验证是命中协商缓存

强缓存

强缓存:不会向服务器发送请求,直接从缓存中读取资源。

2.1 强缓存原理

强制缓存就是向浏览器缓存查找该请求结果,并根据该结果的缓存规则来决定是否使用该缓存结果的过程,强制缓存的情况主要有三种(暂不分析协商缓存过程),如下:

  • 第一次请求,不存在缓存结果和缓存标识,直接向服务器发送请求

缓存 - 图2

存在缓存标识和缓存结果,但是已经失效,强制缓存存在,则使用协商缓存(暂不分析)
缓存 - 图3

  • 存在该缓存结果和缓存标识,且该结果尚未失效,强制缓存生效,直接返回该结果

缓存 - 图4
那么强制缓存的缓存规则是什么?
当浏览器向服务器发起请求时,服务器会将缓存规则放入HTTP响应报文的HTTP头中和请求结果一起返回给浏览器,控制强制缓存的字段分别是ExpiresCache-Control,其中Cache-Control优先级比Expires高。

2.1.1、 Expires

缓存过期时间,用来指定资源到期的时间,是服务器端的具体的时间点。也就是说,Expires=max-age + 请求时间,需要和Last-modified结合使用。Expires是Web服务器响应消息头字段,在响应http请求时告诉浏览器在过期时间前浏览器可以直接从浏览器缓存取数据,而无需再次请求。

Expires 是 HTTP/1 的产物,受限于本地时间,如果修改了本地时间,可能会造成缓存失效。

2.1.2、 Cache-Control

在HTTP/1.1中,Cache-Control是最重要的规则,主要用于控制网页缓存,主要取值为:

  • public:所有内容都将被缓存(客户端和代理服务器都可缓存)
  • private:所有内容只有客户端可以缓存,Cache-Control的默认取值
  • no-cache:客户端缓存内容,但是是否使用缓存则需要经过协商缓存来验证决定
  • no-store:所有内容都不会被缓存,即不使用强制缓存,也不使用协商缓存
  • max-age=xxx (xxx is numeric):缓存内容将在xxx秒后失效

    需要注意的是,no-cache这个名字有一点误导。设置了no-cache之后,并不是说浏览器就不再缓存数据,只是浏览器在使用缓存数据时,需要先确认一下数据是否还跟服务器保持一致,也就是协商缓存。而no-store才表示不会被缓存,即不使用强制缓存,也不使用协商缓存

2.1.3、设置

强缓存需要服务端设置expirescache-control
nginx代码参考,设置了一年的缓存时间:

  1. location ~ .*\.(ico|svg|ttf|eot|woff)(.*) {
  2. proxy_cache pnc;
  3. proxy_cache_valid 200 304 1y;
  4. proxy_cache_valid any 1m;
  5. proxy_cache_lock on;
  6. proxy_cache_lock_timeout 5s;
  7. proxy_cache_use_stale updating error timeout invalid_header http_500 http_502;
  8. expires 1y;
  9. }

3、协商缓存

协商缓存就是强制缓存失效后,浏览器携带缓存标识向服务器发起请求,由服务器根据缓存标识决定是否使用缓存的过程,主要有以下两种情况:

  • 协商缓存生效,返回304和Not Modified

缓存 - 图5

  • 协商缓存失效,返回200和请求结果

缓存 - 图6

ETag和If-None-Match

etaghttp协议提供的若干机制中的一种Web缓存验证机制,并且允许客户端进行缓存协商。生成etag常用的方法包括对资源内容使用抗碰撞散列函数,使用最近修改的时间戳的哈希值,甚至只是一个版本号。 和last-modified一样.

  • 浏览器会先发送一个请求得到etag的值,然后再下一次请求在request header中带上if-none-match:[保存的etag的值]
  • 通过发送的etag的值和服务端重新生成的etag的值进行比对,如果一致代表资源没有改变,服务端返回正文为空的响应,告诉浏览器从缓存中读取资源。

    etag能够解决last-modified的一些缺点,但是etag每次服务端生成都需要进行读写操作,而last-modified只需要读取操作,从这方面来看,etag的消耗是更大的。

二者对比

  • 精确度上:Etag要优于Last-Modified
  • 优先级上:服务器校验优先考虑Etag
  • 性能上:Etag要逊于Last-Modified

参考
https://mp.weixin.qq.com/s/Wvc0lkLpgyEW_u7bbMdvpQ
https://github.com/xiangxingchen/blog/issues/9