浏览器缓存现象
浏览器通过URL地址访问一个网页,显示网页内容的同时会在用户的电脑上面缓存网页内容。如果网页没有更新的话,浏览器再次访问这个URL地址的时候,就不会再次下载网页,而是直接使用本地缓存的网页。只有当网站明确标识资源已经更新,浏览器才会再次下载网页。
一、HTTP缓存涉及的http头
1. Expires(过期时间)HTTP头信息
Expires属性是告诉缓存器缓存在多长时间内是有效的。过了该时间,缓存器就会向源服务器发送请求,检查文档是否被修 改。几乎所有的缓存服务器都支持Expires属性;
Web服务器设置Expires属性的方法有:
- 绝对时间间隔:基于客户最后查看副本的时间(最后访问时间)
- 根据服务器上文档最后被修改的时间
适用范围:
- 对于设置静态图片文件(例如导航栏和图片按钮)可缓存特别有用;因为这些图片修改很少,你可以给它们设置一个特别长的过期时间,这会使你的网站对 用户变得相应非常快;
- 对于控制有规律改变的网页也很有用。例如:你每天早上6点更新新闻页,你可以设置副本的过期时间也是这个时间,这样缓存 服务器就知道什么时候去取一个更新版本,而不必让用户去按浏览器的“刷新”按钮。
时间格式:
只能是HTTP格式的日期时间,其他的都会被解析成当前时间“之前”,副本会过期,记住:HTTP的日期时间必须是格林威治时 间(GMT),而不是本地时间。举例:Expires: Fri, 30 Oct 1998 14:19:41
注意:
- 确认你的Web服务器时间设置正确。
- Web服务器的时间和缓存服务器的时间必须是同步的,如果不同步, 要么是应该缓存的内容提前过期了,要么是过期结果没及时更新。
- 如果设置的过期时间是一个固定的时间,如果返回内容的时候又没有连带更新下次过期的时间,那么之后所有访问请求都会被发送给源Web服务器,反而增加了负载和响应时间;
2. Cache-Control(缓存控制) HTTP头信息
有用的 Cache-Control响应头信息包括:
- max-age=n 单位是秒:从请求时间开始到过期时间之间的秒数,是相对时间间隔,而不是绝对过期时间;
- s-maxage=n 类似于max-age属性,除了他应用于共享(如:代理服务器)缓存;
- public 标记认证内容也可以被缓存,经过HTTP认证才能访问的内容,输出是自动不可以缓存的;
- no-cache 强制每次请求直接发送给源服务器,而不经过本地缓存版本的校验;
- no-store 强制缓存在任何情况下都不要保留任何副本
- must-revalidate 告诉缓存必须遵循所有你给予副本的新鲜度的,HTTP允许缓存在某些特定情况下返回过期数据;
- proxy-revalidate和must-revalidate类似,除了他只对缓存代理服务器起作用
举例:
Cache-Control: max-age=3600, must-revalidate
注意:
- 给静态资源(HTML文件,图片文件等)的Repsone加上Expires/Cache-Control Header是很有效的一招。Expires的值只能是一个固定日期,比如“Thu 27 Nov 2008 07:00:00 GMT”,不能是一个类似“从现在开始之后10年”这样一个随机浮动的值,如果要这样的效果,可以用Cache-Control这样的Header,如果 HTTP Resposne中有这样的Header:“Cache-Control: max-age = 100”,表示这个资源在cache中的最大寿命是100秒。一般说来这种静态文件永远不应该过期,如果真的要给这个Cache加上一个期限,那我希望是 ——一万年,“Cache-Control: max-age = 315360000000”
- 其实就应该给Expires设一个永远不会过期的时间,比如你现在有一个文件叫logo.gif,需要用一个新的logo的时候,你不要去 覆盖原来的文件,而把新的logo存成logo_v2.gif,让相关网页引用新的logo_v2.gif,这样可以让新老网页同时工作,实在犯不上为了 节省存储空间覆盖原有文件。
配置:
对Apache服务器,使用mod_expires,在httpd.conf或者.htaccess中加上<FilesMatch “\\.(ico|gif|jpg|html)$”>ExpiresDefault “access plus 10 years”</FileMatch>
3.Last-Modified/If-Modified-Since
所有现代的浏览器都支持最近修改 (last-modified) 的数据检查。如果你曾经访问过某页,一天后重新访问相同的页时发现它没有变化,并奇怪第二次访问时页面加载得如此之快——这就是原因所在。你的浏览器首次 访问时会在本地缓存页面内容,当你第二次访问,浏览器自动发送首次访问时从服务器获得的最近修改日期。服务器简单地返回 304: Not Modified (没有修改),因此浏览器就会知道从本地缓存加载页面。
4. ETag/If-None-Match
ETag 是实现与最近修改数据检查同样的功能的另一种方法:没有变化时不重新下载数据。其工作方式是:服务器发送你所请求的数据的同时,发送某种数据的 hash (在 ETag 头信息中给出)。hash 的确定完全取决于服务器。当第二次请求相同的数据时,你需要在 If-None-Match: 头信息中包含 ETag hash,如果数据没有改变,服务器将返回 304 状态代码。与最近修改数据检查相同,服务器仅仅 发送 304 状态代码;第二次将不为你发送相同的数据。在第二次请求时,通过包含 ETag hash,你告诉服务器:如果 hash 仍旧匹配就没有必要重新发送相同的数据,因为你还有上一次访问过的数据。
这几个http头可以作为meta标签发送到客户端,但是需要注意的是Http头中的设置优先级更高一些,例如:
<meta http-equiv=”Expires” CONTENT=” Fri, 30 Oct 1998 14:19:41″>
<meta http-equiv=”Cache-Control” CONTENT=”no-cache”>
我们来访问http://www.baidu.com的首页,通过firebug,我们来查看logo图片http://www.baidu.com/img/baidu_logo.gif的headers:
响应头信息
Date | Tue, 10 Aug 2010 09:31:36 GMT |
Server | Apache |
Last-Modified | Tue, 29 Jul 2008 16:00:00 GMT |
Etag | "5d1-4532bbb6ca000" |
Accept-Ranges | bytes |
Content-Length | 1489 |
Cache-Control | max-age=315360000 |
Expires | Fri, 07 Aug 2020 09:31:36 GMT |
Connection | Keep-Alive |
Content-Type | image/gif |
Host | www.baidu.com |
User-Agent | Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 |
Accept | image/png,image/*;q=0.8,*/*;q=0.5 |
Accept-Language | zh-cn,zh;q=0.5 |
Accept-Encoding | gzip,deflate |
Accept-Charset | GB2312,utf-8;q=0.7,*;q=0.7 |
Keep-Alive | 115 |
Connection | keep-alive |
Referer | http://www.baidu.com/ |
Cookie | BAIDUID=60A41CF3CE102AC479459D7202BC7C0C:FG=1; USERID=de28364425ea7fdbeb32a85ecb7beb; BD_UTK_DVT=1 |
Pragma | no-cache |
Cache-Control | no-cache |
F5刷新,第二次查看headers:
响应头信息查看源代码
Date | Tue, 10 Aug 2010 09:37:02 GMT |
Server | Apache |
Connection | Keep-Alive |
Etag | "5d1-4532bbb6ca000" |
Expires | Fri, 07 Aug 2020 09:37:02 GMT |
Cache-Control | max-age=315360000 |
Host | www.baidu.com |
User-Agent | Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 |
Accept | image/png,image/*;q=0.8,*/*;q=0.5 |
Accept-Language | zh-cn,zh;q=0.5 |
Accept-Encoding | gzip,deflate |
Accept-Charset | GB2312,utf-8;q=0.7,*;q=0.7 |
Keep-Alive | 115 |
Connection | keep-alive |
Referer | http://www.baidu.com/ |
Cookie | BAIDUID=60A41CF3CE102AC479459D7202BC7C0C:FG=1; USERID=de28364425ea7fdbeb32a85ecb7beb; BD_UTK_DVT=1 |
If-Modified-Since | Tue, 29 Jul 2008 16:00:00 GMT |
If-None-Match | "5d1-4532bbb6ca000" |
Cache-Control | max-age=0 |
我们可以看到这个图片的最后修改时间和Etag。于是浏览器把这两个状态信息连同网页内容在本地进行缓存,当浏览器再次访问该图片的时候,浏览器会发送如下两个状态标识告诉服务器,我本地缓存的网页最后修改时间和Etag,请问服务器的资源有没有在我上次访问之后有更新啊?于是服务器会核对一下, 如果该用户上次访问之后没有更新过新闻,直接告诉浏览器:“没什么新东西,你还是看自己缓存的网页吧”,于是服务器就发 送一个304 Not Modified的消息,其他什么都不用干了。
二、HTTP缓存有什么用?
1.像Google这种比较智能的网络爬虫可以有效识别资源的状态信息,如果使用这 种缓存机制,可以大大减少爬虫的爬取次数。
2.很多内容更新不频繁的网页,尽管用户不会频繁的刷新,但是从一个比较长的时间段来看使用HTTP Cache,仍然可以起到很大的缓存作用。
3.对于历史帖子使用HTTP缓存。
- 例如,一些历史贴子,很少有人往后面翻页去看历史数据,也就无法被memcache缓存住,那有了http缓存,用户通过收藏夹保存或者其他方式过来,就不必去取数据了。另外爬虫也不会频繁爬去了。
三、如何在应用程序里面使用HTTP缓存
前两种就不说了,直接设置过期时间。重点说说ETAG吧。
1. 适用于新闻列表页,文章列表页等。拿最新一条数据做ETAG,该数据的最后更新时间做Last-Modified时间。
2. 适用于单篇文章页。拿文章最后修改时间和评论数做hash值作为ETAGE,最后更新时间做Lsdt-Modified时间。如果该文章作修改或多一条评论数的话,就认为该页有更新。
等等,具体应用可根据需求来定,发挥大家的思想。
总结
Expires/Cache-Control Header是控制浏览器是否直接从浏览器缓存取数据还是重新发请求到服务器取数据。只是Cache-Control比Expires可以控制的多一些, 而且Cache-Control会重写Expires的规则。
Last-Modified/If-Modified-Since和ETag/If-None-Match是浏览器发送请求到服务器后判断文件是否已经修改过,如果没有修改过就只发送一个304回给浏览器,告诉浏览器直接从自己本地的缓存取数据;如果修改过那就整个数据重新发给浏览器。