HTTP缓存
通过网络获取内容既速度缓慢又开销巨大。较大的响应需要在客户端与服务端之间进行多次往返通信,这会延迟浏览器获得和处理内容的时间,还会增加访问者的流量成本。因此,缓存并重复利用之前获取的资源的能力成为性能优化的一个关键方面。
好在每个浏览器都自带了 HTTP 缓存实现功能。您只需要确保每个服务器响应都提供正确的 HTTP 标头指令,以指示浏览器何时可以缓存响应以及可以缓存多久。
缓存机制
服务器在返回的 Response 中主要使用两个 Header 来控制浏览器的缓存行为.
第一种是 Expires,比如:
Expires:Fri, 02 Jun 2017 11:20:29 GMT
在用一个绝对的时间点来指定文件的有效时间,在此日期之前,客户端都会认为缓存是有效的,第二次请求,浏览器不会连接服务器,直接从本地缓存中读取.
第二种是 Cache-Control,比如:
Cache-Control:max-age=691200
Cache-Control在 HTTP 1.1版本中定义,除了提供了同Expires相同并更精确的缓存功能,还提供了验证机制,它可以取以下这些值:
max-age:功能和Expires类似,但是后面跟一个以“秒”为单位的相对时间,来供浏览器计算过期时间。
no-cache:当浏览器在下次请求相同资源时,会向服务端 发送请求,并带上相关验证 Header 字段,让服务端 判断资源是否过期,并决定是返回该资源新的内容(状态码200,已过期),或是返回资源未修改的标识给客户端使其从缓存中读取(状态码304,Not Modified)。其中相应的验证 Header 字段和判断方法会在下文介绍。
no-store:表示当前请求资源禁用缓存。
private:指示只有用户客户端可以缓存,而 CDN 等不可。
public:指示用户客户端和 CDN 都可以缓存当前资源。
注:Expires来自于HTTP1.0,Cache-Control来自于HTTP1.1,Cache-Control优先级高于Expires
验证机制
当设置了 no-cache 时,服务端 如何判断是否需要返回文件内容呢?有以下两种方式。
Last-Modified:Tue, 30 May 2017 09:13:46 GMT
当浏览器第二次请求同样的 URL 时,根据 HTTP 协议的规定,浏览器会向服务器发送 If-Modified-Since 报头,询问该时间之后文件是否有被修改过。比如:
If-Modified-Since:Tue, 30 May 2017 09:13:46 GMT
如果服务端判断资源已经过期,则返回该资源新的内容(状态码200,已过期),如果服务端判断资源没有过期,则返回资源未修改的标识给客户端使其从缓存中读取(状态码304,Not Modified)。
304:通过If-Modified-Since
If-Match判断资源是否修改,如未修改则返回304,发生了一次请求,但请求内容长度为0,节省了带宽。
注:在 Chrome 的开发者工具中勾选 Disable cache 选项后,发送的请求会去掉If-Modified-Since这个 Header。
Etag:"236f2c8c3b27b143393df0104777f43a"
客户端的查询更新格式是这样的:
If-None-Match:"236f2c8c3b27b143393df0104777f43a"
如果ETag没改变,则返回状态304,这也和Last-Modified一样。
注:当同时设置时,ETag 验证方式的优先级要高于 Last-Modified 的验证方式。
总结
浏览器第一次请求:
浏览器再次请求:
图片来源:吴秦博客(http://www.cnblogs.com/skynet/archive/2012/11/28/2792503.html)