通过网络获取内容既缓慢,成本又高:大的响应需要在客户端和服务器之间进行多次往返通信,这拖延了浏览器可以使用和处理内容的时间,同时也增加了访问者的数据成本。因此,缓存和重用以前获取的资源的能力成为优化性能很关键的一个方面。
浏览器端缓存的机制有很多种,总体归纳为九种,打开浏览器的调试模式->resources左侧就有浏览器的8种缓存机制。
本文主要来了解HTTP缓存。http缓存是基于HTTP协议的浏览器文件级缓存机制。即针对文件的重复请求情况下,浏览器可以根据协议头判断从服务器端请求文件还是从本地读取文件,chrome控制台下的Frames即展示的是浏览器的http文件级缓存。
HTTP缓存由服务器响应的首指令控制,以指导浏览器何时可以缓存响应以及可以缓存多久。
Expires/Cache-Control
浏览器第一次请求时,服务器在返回响应时,还会发出一组 HTTP 头,用来指导浏览器如何进行缓存。
我们来思考以下,服务器指导浏览器进行缓存,都要告诉浏览器哪些信息。
首先,服务器肯定要规定这个资源是否要进行缓存。这主要由响应头中的Expires/Cache-Control两个字段来控制。
Expires字段是http1.0时的规范,它的值为一个绝对时间的GMT格式的时间字符串,比如Expires:Mon,18 Oct 2066 23:59:59 GMT。这个时间代表着这个资源的失效时间。
Cache-Control是http1.1时出现的header信息,主要是利用该字段的max-age值来进行判断,它是一个相对时间,例如Cache-Control:max-age=3600,代表着资源的有效期是3600秒。Cache-Control,还有几个比较常用的设置值:
- no-cache:不使用本地缓存。需要使用缓存协商,先与服务器确认返回的响应是否被更改,如果之前的响应中存在ETag,那么请求的时候会与服务端验证,如果资源未被更改,则可以避免重新下载。
- no-store:直接禁止游览器缓存数据,每次用户请求该资源,都会向服务器发送一个请求,每次都会下载完整的资源。
- public:可以被所有的用户缓存,包括终端用户和CDN等中间代理服务器。
- private:只能被终端用户的浏览器缓存,不允许CDN等中继缓存服务器对其缓存。
Cache-Control与Expires:
1.Expires 失效时间是一个绝对时间,所以当服务器与客户端时间偏差 较大时,就会导致缓存混乱。 Cache-Control的max-age是一个相对时间.
2.可以在服务端配置同时启用,同时启用的时候Cache-Control优先级高。
下次请求时,浏览器会先获取该资源缓存的header信息,根据Expires/Cache-Control字段判断请求时间,如果下次请求时间在这个时间以前,则可以直接从缓存中获取资源,不必与服务器进行通信。我们把这种机制称为强缓存。注意强缓存时,返回的状态码为200,并会注明来自磁盘缓存。
如果下次请求时间超过缓存有效期,浏览器就会发送请求到服务器,由服务器来决定下一步该怎么办,这个过程称为协商缓存。
Etag/If-None-Match和Last_Modified/If-Modify-Since
那服务器进行缓存协商的依据又是什么呢?这主要由响应首部字段中的Etag/Last_Modified字段决定。
Last_Modified字段是http1.0时的规范,他是标识该资源的最后修改时间,例如Last-Modify: Thu,31 Dec 2037 23:59:59 GMT。
当浏览器再次请求该资源时,request的请求头中会包含If-Modify-Since,该值为缓存之前返回的Last-Modify。服务器收到If-Modify-Since后,根据资源的最后修改时间判断是否命中协商缓存。若命中,则浏览器返回304响应,并更新缓存中的相应头信息。否则,返回最新的资源内容。
Etag是http1.1时的规范,当浏览器第一次请求一个文件时,服务器会生成并返回一个随机令牌即Etag,通常是文件内容的哈希值或者某个其他指纹码。客户端不必了解指纹码是如何生成的,只需要在下一个请求中通过If-None-Match字段将其发送给服务器:如果指纹码仍然一致,说明资源未被修改,返回304。如果不一致,说明 资源已修改,则返回最新的资源内容。
Last-Modified与ETag:
1.HTTP1.1中Etag的出现主要是为了解决几个Last-Modified比较难解决的问题:
- 一些文件也许会周期性的更改,但是他的内容并不改变(仅仅改变的修改时间),这个时候我们并不希望客户端认为这个文件被修改了,而重新GET;
- 某些文件修改非常频繁,比如在秒以下的时间内进行修改,(比方说1s内修改了N次),If-Modified-Since能检查到的粒度是s级的,这种修改无法判断(或者说UNIX记录MTIME只能精确到秒);
- 某些服务器不能精确的得到文件的最后修改时间。
2.是可以一起使用的,服务器会优先验证ETag,一致的情况下,才会继续比对Last-Modified,最后才决定是否返回304。
更新或废弃已缓存的响应
缓存是一个让我们既欣喜又头疼的问题,比如,设计人员刚刚提交了一个更新,我们希望所有用户都能使用。但由于 max-age /expires 的指定,在缓存过期以前,用户拿到的依然是缓存中旧的版本,除非用户清除浏览器缓存,但很显然,这个我们无法控制。那该怎么办呢?
很简单,在资源内容更改时,我们可以更改资源的网址,强制用户下载新响应。通常情况下,可以通过在文件名中嵌入文件的指纹码(或版本号)来实现 - 例如 style.x234dff.css。
总结
参考:
http://caibaojian.com/browser-cache.html
http://jixianqianduan.com/frontend-javascript/2015/12/28/nine-browser-cache-methods.html