一张图理解Http缓存

参阅了一些浏览器缓存的资料,本文经过一张图来概括总结其过程。html

浏览器第一次向一个web服务器发起http请求后,服务器会返回请求的资源,而且在响应头中添加一些有关缓存的字段如:Cache-ControlExpiresLast-ModifiedETagDate等等。以后浏览器再向该服务器请求该资源就能够视状况使用强缓存协商缓存web

  • 强缓存:浏览器直接从本地缓存中获取数据,不与服务器进行交互。
  • 协商缓存:浏览器发送请求到服务器,服务器断定是否可以使用本地缓存。
  • 联系与区别:两种缓存方式最终使用的都是本地缓存;前者无需与服务器交互,后者须要。

下面假定浏览器已经访问了服务器,服务器返回了缓存相关的头部字段且浏览器已对相关资源作好缓存。经过下图来分析强缓存和协商缓存:浏览器

clipboard.png

强缓存

如图红线所示的过程表明强缓存。用户发起了一个http请求后,浏览器发现先本地已有所请求资源的缓存,便开始检查缓存是否过时。有两个http头部字段控制缓存的有效期:ExpiresCache-Control,浏览器是根据如下两步来断定缓存是否过时的:缓存

  1. 查看缓存是否有Cache-Controls-maxagemax-age指令,如有,则使用响应报文生成时间Date + s-maxage/max-age得到过时时间,再与当前时间进行对比(s-maxage适用于多用户使用的公共缓存服务器);
  2. 若是没有Cache-Controls-maxagemax-age指令,则比较Expires中的过时时间与当前时间。Expires是一个绝对时间。

注意,在HTTP/1.1中,当首部字段Cache-Control有指定s-maxagemax-age指令,比起首部字段Expires,会优先处理s-maxagemax-age服务器

另外下面列几个Cache-Control的经常使用指令:spa

  • no-cache:含义是不使用本地缓存,须要使用协商缓存,也就是先与服务器确认缓存是否可用。
  • no-store:禁用缓存。
  • public:代表其余用户也可以使用缓存,适用于公共缓存服务器的状况。
  • private:代表只有特定用户才能使用缓存,适用于公共缓存服务器的状况。

通过上述两步判断后,若缓存未过时,返回状态码为200,则直接从本地读取缓存,这就完成了整个强缓存过程;若是缓存过时,则进入协商缓存或服务器返回新资源过程。code

协商缓存

当浏览器发现缓存过时后,缓存并不必定不能使用了,由于服务器端的资源可能仍然没有改变,因此须要与服务器协商,让服务器判断本地缓存是否还能使用。此时浏览器会判断缓存中是否有ETagLast-Modified字段,若是没有,则发起一个http请求,服务器根据请求返回资源;若是有这两个字段,则在请求头中添加If-None-Match字段(有ETag字段的话添加)、If-Modified-Since字段(有Last-Modified字段的话添加)。注意:若是同时发送If-None-MatchIf-Modified-Since字段,服务器只要比较If-None-MatchETag的内容是否一致便可;若是内容一致,服务器认为缓存仍然可用,则返回状态码304,浏览器直接读取本地缓存,这就完成了协商缓存的过程,也就是图中的蓝线;若是内容不一致,则视状况返回其余状态码,并返回所请求资源。下面详细解释下这个过程:htm

1.ETagIf-None-Match

两者的值都是服务器为每份资源分配的惟一标识字符串。blog

  • 浏览器请求资源,服务器会在响应报文头中加入ETag字段。资源更新时,服务器端的ETag值也随之更新;
  • 浏览器再次请求资源时,会在请求报文头中添加If-None-Match字段,它的值就是上次响应报文中的ETag的值;
  • 服务器会比对ETagIf-None-Match的值是否一致,若是不一致,服务器则接受请求,返回更新后的资源;若是一致,代表资源未更新,则返回状态码为304的响应,可继续使用本地缓存,要注意的是,此时响应头会加上ETag字段,即便它没有变化。

2.Last-ModifiedIf-Modified-Since

两者的值都是GMT格式的时间字符串。ip

  • 浏览器第一次向服务器请求资源后,服务器会在响应头中加上Last-Modified字段,代表该资源最后一次的修改时间;
  • 浏览器再次请求该资源时,会在请求报文头中添加If-Modified-Since字段,它的值就是上次服务器响应报文中的Last-Modified的值;
  • 服务器会比对Last-ModifiedIf-Modified-Since的值是否一致,若是不一致,服务器则接受请求,返回更新后的资源;若是一致,代表资源未更新,则返回状态码为304的响应,可继续使用本地缓存,与ETag不一样的是:此时响应头中不会再添加Last-Modified字段。

3.ETag较之Last-Modified的优点

如下内容引用于:http协商缓存VS强缓存

你可能会以为使用Last-Modified已经足以让浏览器知道本地的缓存副本是否足够新,为何还须要ETag呢?HTTP1.1ETag的出现主要是为了解决几个Last-Modified比较难解决的问题:

  • 一些文件也许会周期性的更改,可是他的内容并不改变(仅仅改变的修改时间),这个时候咱们并不但愿客户端认为这个文件被修改了,而从新GET
  • 某些文件修改很是频繁,好比在秒如下的时间内进行修改,(比方说1s内修改了N次),If-Modified-Since能检查到的粒度是s级的,这种修改没法判断(或者说UNIX记录MTIME只能精确到秒);
  • 某些服务器不能精确的获得文件的最后修改时间。

这时,利用ETag可以更加准确的控制缓存,由于ETag是服务器自动生成的资源在服务器端的惟一标识符,资源每次变更,都会生成新的ETag值。Last-ModifiedETag是能够一块儿使用的,但服务器会优先验证ETag

用户行为

最后附一张图说明用户行为对浏览器缓存的影响:
clipboard.png