浏览器是如何根据header进行缓存的?

来源:互联网 发布:直饮水 知乎 编辑:程序博客网 时间:2024/05/17 06:00

看到好多介绍浏览器缓存的文章,但是都感觉介绍得云里雾里的,还是亲自动手尝试了一遍大笑,发现好多文章其实都存在一定的问题,下面先来个图来说明大概结构。



浏览器只有在max-age或者Epires到期后,才会发出http请求到服务器,然后服务器会根据If-Modified-Since或者If-None-Match值来进行比较,判断浏览器中的信息是否过期,如果未过期的话,返回一个304让浏览器继续把那些信息保存着(同时会附带一个新的max-age)。


所以整个过程可以这样理解,max-age和Expires是让浏览器闭嘴的,时间没到浏览器不会开口,然后到了时间之后,浏览器就会很烦地问一句request:“东西有没有更新了?”。服务器检查一下If-Modified-Since或者If-None-Match,就会发回一句304状态码:“尼玛叫你别说话还说!回去闭嘴呆着!“或200状态码:“好吧,你赢了,东西更新了。。”


现在来说一下前面提到的If-Modified-Since和If-None-Match

RequestResponseIf-Modified-SinceIf-ModifiedIf-None-MatchETag
这两个都一一对应关系。比如服务器给浏览器的是ETag,在请求的时候浏览器发回的就不是ETag了,而是If-None-Match。

那既然两个都能作为是否更改的特征,那有什么区别呢?

Etag 主要为了解决 Last-Modified 无法解决的一些问题。1. 一些文件也许会周期性的更改,但是他的内容并不改变(仅仅改变的修改时间),这个时候我们并不希望客户端认为这个文件被修改了,而重新GET;2. 某些文件修改非常频繁,比如在秒以下的时间内进行修改,(比方说1s内修改了N次),If-Modified-Since能检查到的粒度是s级的,这种修改无法判断(或者说UNIX记录MTIME只能精确到秒);3. 某些服务器不能精确的得到文件的最后修改时间;为此,HTTP/1.1引入了 Etag(Entity Tags).Etag仅仅是一个和文件相关的标记,可以是一个版本标记,比如说v1.0.0或者说"2e681a-6-5d044840"这么一串看起来很神秘的编码。但是HTTP/1.1标准并没有规定Etag的内容是什么或者说要怎么实现,唯一规定的是Etag需要放在""内。

摘自百度百科


下面来讲一下本来在实际缓存测试中遇到的问题,如果需要还原浏览器根据max-age或Expires来进行缓存的情景,千万不能按F5或者刷新,那样一定会发出http包,而很多文章中讲到,用回车来进行的话,可以还原出缓存场景,其实那些文章没有说全,我在这个坑里至少待了1个小时,按了无数个回车,但是http包都很开心地发出去了。

其实正确的做法应该是新开一个标签页,然后将网址粘贴上去,然后按回车,那么这一次就会读取浏览器缓存(如果还没过期的话)。而如果前一个网址和这个网址是相同的话,浏览器会自动认为是刷新操作,http包就毫无保留地蹦出去了,所以在同个网页中,F5;刷新按钮;没有更改网址然后回车,这三个是一样一样的。



小提示 max-age VS Expires

Expires有个天然的缺陷就是服务器时间和浏览器时间的同步问题,因为这是一个绝对时间,如果服务器时间和浏览器时间差很多的话,会导致不用缓存的存很久或者该缓存的一次也没存。

max-age本身就是秒数,这是一个相对时间,与服务器的时间无关,就不会有Expires的缺陷,作用就是从http包拿到后开始本地计时,超过那个秒数就会过期。

上文提到的304返回包可以对max-age进行续期,当浏览器max-age到期后,浏览器会发出http请求包,而服务器如果发现资源未变更,返回的304状态也会携带一个max-age,这个时候max-age又会用新的max-age值重新进行计数(如果用F5刷新道理相同,只是在未到期时就进行续期)。

max-age和Expires的优先级为max-age,Expires是HTTP 1.0的,而max-age(HTTP 1.1)用来计算缓存时间更为合适,所以只要有max-age,浏览器一定会用max-age来计算。

除了IE的那几款只知道Expires,导致现在发的包必须同时携带max-age和Expires,可以让http包在碰到IE的时候也能兼容。



附缓存测试php文件


<?phpecho '这是一个缓存测试!'.date('Y-m-d H:i:s');$time = time();$interval = 60 * 5; //秒数header('Last-Modified: '.gmdate('r', $time + $interval));header('Expires: '.gmdate('r',($time + $interval)));header('Cache-Control: max-age='.$interval);?>


OpenCDN团队