#http cache
在调试问题时经常因为cache而导致一些问题被忽略,所以了解cache还是很有必要的
HTTP 1.0/1.1推出了Expires/Cache-Control两种策略,目前 HTTP1.0 已经很少见了,所有我们重点关注HTTP1.1的Cache-Control。
拿腾讯网为例,在浏览器输入 www.qq.com
,用fiddler抓包返回:
Cache-Control: max-age=60
Date: Mon, 20 Jan 2014 13:12:36 GMT
Expires: Mon, 20 Jan 2014 13:13:36 GMT
X-Cache: HIT from shenzhen.qq.com
其中max-age为60表示缓存60秒,并且Date + max-age = Expires;
通常对于静态资源还有一个Last-Modified和ETag,比如:
ETag: "c27426b8a4ffce1:0"
Last-Modified: Mon, 20 Jan 2014 13:21:17 GMT
只使用Expires
验证,存在服务器时间和客户端时间不一致导致浏览器无法准确判断文件是否从缓存读取的问题;
使用Date + max-age
验证时,当页面刷新(点击浏览器上的刷新按钮、按F5、在地址栏输入地址回车)时,客户端发送的请求中均是max-age=0,表示validate操作,发送请求到服务器要求检查cache,再更新cache,服务器根据If-Modified-Since(Last-Modified)和ETag判断文件是否更新(即是否应该响应304 Not Modified),这也是HTTP1.1开始使用Cache-Control而不用Expires的原因。
既然有了Last-Modified,为什么还要用ETag字段呢?
因为如果在一秒钟之内对一个文件进行两次更改,Last-Modified就会不正确。因此,HTTP/1.1利用Entity Tag 头提供了更加严格的验证。
// 页面刷新时的 Request Headers
Cache-Control: max-age=0
If-Modified-Since: Mon, 23 Dec 2013 06:03:36 GMT // Last-Modified
If-None-Match: "c27426b8a4ffce1:0" // ETag
Request Headers的Cache-Control行为分析:
no-cache: 强制每次请求直接发送给源服务器,而不经过本地缓存版本的校验。这对于需要确认认证应用很有用(可以和public结合使用),或者严格要求使用最新数据的应用;
max-age>0: 直接从游览器缓存中读取;
max-age<=0: 向server发送http请求确认该资源是否有修改,有的话返回200,没有的话返回304。
当按Ctrl+F5强制刷新时,Cache-Control为no-cache,同时Pragma为no-cache,应用程序向原始服务器推送此请求,即使它已经在上次请求时缓存了一份拷贝,这样将保证客户端能接收到最权威的回应,它也用来在客户端发现其缓存中拷贝不可用或过期时,对拷贝进行强制刷新。
这里还有一个X-Cache,表示数据是从CDN返回的,与X-Cache相关的还有X-Cache-Lookup,值一般为 HIT xxx 或者 MISS xxx,一般来说两个会有一个是HIT,具体规则:
- 文件在squid中超过了refresh_p参数设置的时间,访问的时候会去后端验证,这个时候X-Cache返回的是MISS,但发现后端文件并没有更新,所以squid继续使用cache文件,X-Cache-Lookup返回的就是HIT;
- 客户端给了一个Ctrl+F5,但refresh_pattern参数中设置了reload-into-ms,这时文件也会到后端验证,同样X-Cache返回的是MISS,但后端告诉squid文件未更新,所以squid继续从cache返回给客户端,X-Cache-Lookup返回的就是HIT。
更多内容请参考: