http的cache

http://blog.csdn.net/shine0181/article/details/6084542

HTTP Cache 学习2009-08-20 14:18  

http协议里控制浏览器缓存的头有三个Cache-Control,Expires,Last-Modified
对于静态页面还有Etag。
一、先来看第一种情况:apache 静态页面
apache发送给客户端的静态页面一般包含Last-Modified和Etag,这两个标签的值来自静态文件的修改时间和inode,
下面是截取得apache返回客户端的头
---------
Last-Modified: Fri, 26 Jan 2007 01:53:34 GMT
ETag: "3f9f640-318-cb9f8380"
---------
搜索引擎之所以喜欢静态文件是因为有这两个标识,可以判断文件是否更新过
二、PHP等动态页面
由于php是动态生成的,它的内容是不能根据php程序的时间来确定最后修改日期,所以默认php返回客户端的时候补包含任何缓存控制,要想利用好缓存就必须了解缓存机制,和理减少b,s的交互,缩减带宽流量,减轻服务器负担...好处多多
三、缓存控制的具体含义
先解释一下本人经过测试理解的这几个标签的含义
Cache-Control:指定请求和响应遵循的缓存机制。在请求消息或响应消息中设置Cache-Control并不会修改另一个消息处理过程中的缓 存处理过程。请求时的缓存指令包括no-cache、no-store、max-age、max-stale、min-fresh、only-if- cached,响应消息中的指令包括public、private、no-cache、no-store、no-transform、must- revalidate、proxy-revalidate、max-age。各个消息中的指令含义如下:
Public指示响应可被任何缓存区缓存。
Private指示对于单个用户的整个或部分响应消息,不能被共享缓存处理。这允许服务器仅仅描述当用户的部分响应消息,此响应消息对于其他用户的请求无效。
no-cache指示请求或响应消息不能缓存
no-store用于防止重要的信息被无意的发布。在请求消息中发送将使得请求和响应消息都不使用缓存。
max-age指示客户机可以接收生存期不大于指定时间(以秒为单位)的响应。
min-fresh指示客户机可以接收响应时间小于当前时间加上指定时间的响应。
max-stale指示客户机可以接收超出超时期间的响应消息。如果指定max-stale消息的值,那么客户机可以接收超出超时期指定值之内的响应消息。
php用法:
在输出之前用header(),(如果使用ob_start()可以将header放在程序任意地方)
header('Cache-Control: max-age=8');
max-age=8表示最大生存期8秒,超过8秒浏览器必须去服务器重新读取,这个时间是以用户的读取页面开始计时的,而Expires是绝对时间。
Expires:缓存过期的绝对时间,如果过了它指定的那个时间点,浏览器就不认缓存了,要去服务器重新请求一份最新的。
Last-Modified:文档的最后修改时间,它的妙用就是:1 如果是静态文件,客户端会发上来它缓存里的时间,apache会来比对,如果发现没有修改就直接返回一个头,状态码是304,字节数非常少,(高级版本还会增加比较Etag来确定文件是否变化)
2 php动态文件: 客户端发上比对时间,php会判断是否修改,如果修改时间相同,就只会返回1024字节,至于为什么返回1024不得而知,如果你 的php生成的文件非常大,它也只返回1024,所以比较省带宽,客户端会根据服务器端发过来的修改时间自动从缓存文件里显示。
注:如果没有Last-Modified头,Cache-Control和Expires也是可以起作用的,但每次请求要返回真实的文件字节数,而不是1024
四、HOW ?
静态页面不用去管它了,如果想更好的控制静态页面的缓存,apache有几个模块可以很好的控制,这里不讨论
php页面:
这里分两种:1 不经常改动的页面,类似新闻发布,这类页面的特点:第一次发布之后会有几次改动,随着时间推移基本不会再修改。控制策略应该是:1第一次 发布之发送Last-Modified,max-age设定1天,修改过之后更新Last-Modified,max-age时间随着修改次数正常。这样 似乎比较繁琐,还要记录修改次数,也可以预计一下下次可能的修改时间用Expires指定到大概时间过期
php代码:
//header('Cache-Control: max-age=86400');//缓存一天
header('Expires: Mon, 29 Jan 2007 08:56:01 GMT');//指定过期时间
header('Last-Modified: '.gmdate('D, d M Y 01:01:01',$time).' GMT');//格林尼治时间,$time是文件添加时候的时间戳
2 经常改动的页面   类似bbs,论坛程序,这种页面更新速度比较快,缓存的主要作用是防止用户频繁刷新列表,导致服务器数据库负担,既要保证更新的及时性,也要保证缓存能被利用
这里一般用Cache-Control来控制,根据论坛的发帖的频率灵活控制max-age。
header('Cache-Control: max-age=60');//缓存一分钟
header('Last-Modified: '.gmdate('D, d M Y 01:01:01',$time).' GMT');//格林尼治时间,$time是帖子的最后更新时间戳
五 额外
1 刷新,转到,强制刷新的区别
浏览器上有刷新和转到按键,有的浏览器支持用ctrl+F5强制刷新页面,它们的区别是什么?
转到:用户点击链接就是转到,它完全使用缓存机制,如果有Last-Modified那么不会和服务器通讯,用抓包工具可以查看到发送字节是0byte,如果缓存过期,那么它会执行F5刷新的动作。
刷新(F5):这种刷新也是根据缓存是否有Last-Modified来决定,如果有会转入304或1024(php),如果没有最后更新时间那么去服务器读取,返回真实文档大小
强制刷新:完全抛弃缓存机制,去服务器读取最新文档,向服务器发送的header如下
Cache-Control: no-cache
2 调试工具
查看浏览器和服务器交互比较好的工具是httpwatch pro,现在的版本4.1,支持ie7

还有别的代理抓包工具可以分析,http debugging。没用过,还有tcp抓包工具,2000自带的network monitor不过不是专门针对http的比较难用





  HTTP协议中,关于一些头域的解释很模糊,网上的解释有些甚至是打架的,例如cache-control:no-cache。

     http header中cache-control无疑是非常重要的一个头,往往涉及到性能问题,缓存,缓存代理等等都无法避免跟cache-control打交道。
     当然还有其他一些头域如last-modified,但它们含义都非常明确,至少没有cache-control那么含糊。

     就连浏览器之间,对cache-control也有不同的理解,导致了对这个头的不同的表现。

网上很多关于cache-control的资料写得很模糊,我觉得很多都没有,或者可能是忽略了几个地方,使得我们看着这些资料的时候,似懂非懂。或者作者觉得某些地方足够容易理解,所以根本不觉得需要强调,但正是这些被忽略掉的“前提条件”令我们即使看完资料,也很难弄懂问题。那些对cache-control进行解释的资料通常会忽略的一些"前提条件"有这几个:

1.cache-control是出现在response还是request中。很多资料在解释cache-control时候,都没有指明是response中的cache-control(也就是由服务器应答时发送的cache-control)还是request中的cache-control(也就是由用户代理,通常是浏览器,请求资源时发送的cache-control)。

2.什么是缓存。“缓存”一词会有N种解释,特别是一些翻译自英文的资料。“缓存”可以指缓存的对象(object),也可以指HTTP消息链上的缓存系统,例如浏览器的缓存系统,和代理服务器上的缓存,或者一些专为缓存而设计的代理服务器(例如squid),也可以是原始服务器上的缓存(例如c#的cache对象)。而另一方面,根据语境不同,“缓存”也有可能指缓存的机制....N多。所以一些资料当忽略了这些,读者看了后,旧疑问还没搞清楚,又来了新疑问。

而说到HTTP链上的缓存系统,我们一般指浏览器的缓存系统,和代理服务器的缓存。

关于cache-control指令的一些情况:

当cache-control出现在request中:
cache-control:no-control 告诉HTTP消息链上的缓存系统(也就是浏览器的缓存和代理服务器上的缓存),本次请求要求忽略一齐缓存,必须是原始服务器重新计算生成回应给用户。所以,即使浏览器上的本地缓存未过期,或者代理服务器上的缓存未过期,都不要将这些缓存作为回应。当我们在浏览器中强制刷新页面(按ctrl+F5),发送的就是这个头(不同很多浏览器将cache-contro:no-cachel和pragam:no-cache两个头一起发送)

pragma:no-cache:和cache-control:no-control一样,不过出于兼容HTTP/1.0,所以有些浏览器会保留这个头。注意pragma:no-cache只应该出现在Request中,表明不想获取缓存。HTTP没有哪条条文对Response中的pragma:no-cache进行定义,所以Response中的pragma:no-cache是无效的。

当cache-control出现在response中:
cache-control:no-control 服务器告诉HTTP消息链上的缓存系统,不要缓存这个response结果。其实这个不是百分百肯定,而且不同浏览器好像接收到这个头时也有不同反应。

当response header有cache-control:no-control时:
chrome:再访问相同的URL时候是发出if-modified-since。这说明即使接收到cache-control:no-contro,chrome也会进行缓存。

IE9:再次访问相同URL时,跟第一次访问(无缓存情况下)一样,没有if-modified-since,也没有其他缓存相关的头域,而且缓存文件夹也没有缓存文件。也就是说,IE9接收到cache-control:no-contro,不会将response内容缓存起来。

FF:跟IE9行为类似

而另外,cache-control:no-store出现在response中才有意义,意思是告诉缓存系统不要缓存或者存储response内容(不要任何形式的存储,包括存储在缓存文件夹中,以免一些敏感信息外泄)。chrome,IE9,FF对这个头的实现是一样的。当接收到有这个头的response,三个浏览器的缓存目录都找不到相关的缓存文件。




基础知识
  1) 什么是”Last-Modified”?
  在浏览器第一次请求某一个URL时,服务器端的返回状态会是200,内容是你请求的资源,同时有一个Last-Modified的属性标记此文件在服务期端最后被修改的时间,格式类似这样:
  Last-Modified: Fri, 12 May 2006 18:53:33 GMT
  客户端第二次请求此URL时,根据 HTTP 协议的规定,浏览器会向服务器传送 If-Modified-Since 报头,询问该时间之后文件是否有被修改过:
  If-Modified-Since: Fri, 12 May 2006 18:53:33 GMT
  如果服务器端的资源没有变化,则自动返回 HTTP 304 (Not Changed.)状态码,内容为空,这样就节省了传输数据量。当服务器端代码发生改变或者重启服务器时,则重新发出资源,返回和第一次请求时类似。从而保证不向客户端重复发出资源,也保证当服务器有变化时,客户端能够得到最新的资源。
  2) 什么是”Etag”?
  HTTP 协议规格说明定义ETag为“被请求变量的实体值” (参见 —— 章节 14.19)。 另一种说法是,ETag是一个可以与Web资源关联的记号(token)。典型的Web资源可以一个Web页,但也可能是JSON或XML文档。服务器单独负责判断记号是什么及其含义,并在HTTP响应头中将其传送到客户端,以下是服务器端返回的格式:
  ETag: "50b1c1d4f775c61:df3"
  客户端的查询更新格式是这样的:
  If-None-Match: W/"50b1c1d4f775c61:df3"
  如果ETag没改变,则返回状态304然后不返回,这也和Last-Modified一样。本人测试Etag主要在断点下载时比较有用。
  Last-Modified和Etags如何帮助提高性能?
  聪明的开发者会把Last-Modified 和ETags请求的http报头一起使用,这样可利用客户端(例如浏览器)的缓存。因为服务器首先产生 Last-Modified/Etag标记,服务器可在稍后使用它来判断页面是否已经被修改。本质上,客户端通过将该记号传回服务器要求服务器验证其(客户端)缓存。


过程如下:
1,客户端请求一个页面(A)。

2,服务器返回页面A,并在给A加上一个Last-Modified/ETag。

3,客户端展现该页面,并将页面连同Last-Modified/ETag一起缓存。

4,客户再次请求页面A,并将上次请求时服务器返回的Last-Modified/ETag一起传递给服务器。

5,服务器检查该Last-Modified或ETag,并判断出该页面自上次客户端请求之后还未被修改,直接返回响应304和一个空的响应体。

 

------------------------------------------------------------------------------------------------

正确使用Etag和Expires标识处理,可以使得页面更加有效被Cache。
在客户端通过浏览器发出第一次请求某一个URL时,根据 HTTP 协议的规定,浏览器会向服务器传送报头(Http Request Header),服务器端响应同时记录相关属性标记(Http Reponse Header),服务器端的返回状态会是200,格式类似如下:
HTTP/1.1 200 OK
Date: Tue, 03 Mar 2009 04:58:40 GMT
Content-Type: image/jpeg
Content-Length: 83185
Last-Modified: Mon, 22 Nov 2010 16:29:24 GMT
Cache-Control: max-age=2592000

Expires: Thu, 02 Apr 2009 05:14:08 GMT
Etag: "xok.la-961AA72-4CEA99B4415628″客户端第二次请求此URL时,根据 HTTP 协议的规定,浏览器会向服务器传送报头(Http Request Header),服务器端响应并记录相关记录属性标记文件没有发生改动,服务器端返回304,直接从缓存中读取:
HTTP/1.x 304 Not Modified
Date: Tue, 03 Mar 2009 05:03:56 GMT
Content-Type: image/jpeg
Content-Length: 83185
Last-Modified: Mon, 22 Nov 2010 16:29:24 GMT
Cache-Control: max-age=2592000
Expires: Thu, 02 Apr 2009 05:14:08 GMT
Etag: "xok.la-961AA72-4CEA99B4415628″其中Last-Modified、Expires和Etag是标记页面缓存标识


一、Last-Modified、Expires和Etag相关工作原理
1、Last-Modified
在浏览器第一次请求某一个URL时,服务器端的返回状态会是200,内容是你请求的资源,同时有一个Last-Modified的属性标记 (Http Reponse Header)此文件在服务期端最后被修改的时间,格式类似这样:
Last-Modified: Mon, 22 Nov 2010 16:29:24 GMT客户端第二次请求此URL时,根据 HTTP 协议的规定,浏览器会向服务器传送 If-Modified-Since 报头(Http Request Header),询问该时间之后文件是否有被修改过:
If-Modified-Since: Mon, 22 Nov 2010 16:29:24 GMT如果服务器端的资源没有变化,则自动返回 HTTP 304 (NotChanged.)状态码,内容为空,这样就节省了传输数据量。当服务器端代码发生改变或者重启服务器时,则重新发出资源,返回和第一次请求时类 似。从而保证不向客户端重复发出资源,也保证当服务器有变化时,客户端能够得到最新的资源。
注:如果If-Modified-Since的时间比服务器当前时间(当前的请求时间request_time)还晚,会认为是个非法请求
2、Etag工作原理
HTTP 协议规格说明定义ETag为”被请求变量的实体标记” (参见14.19)。简单点即服务器响应时给请求URL标记,并在HTTP响应头中将其传送到客户端,类似服务器端返回的格式:
Etag: "xok.la-961AA72-4CEA99B4415628″客户端的查询更新格式是这样的:
If-None-Match: "xok.la-961AA72-4CEA99B4415628″如果ETag没改变,则返回状态304。
即:在客户端发出请求 后,Http Reponse Header中包含 Etag: “xok.la-961AA72-4CEA99B4415628″
标识,等于告诉Client端,你拿到的这个的资源有表示 ID:xok.la-961AA72-4CEA99B4415628。当下次需要发Request索要同一个 URI的时候,浏览器同时发出一个If-None-Match报头( Http RequestHeader)此时包头中信息包含上次访问得到的Etag: “xok.la-961AA72-4CEA99B4415628″标识。
If-None-Match: "xok.la-961AA72-4CEA99B4415628",这样,Client端等于Cache了两份,服务器端就会比对2者的etag。如果 If- None-Match为False,不返回200,返回304 (Not Modified) Response。
3、Expires
给出的 日期/时间后,被响应认为是过时。如Expires: Thu, 02 Apr 2009 05:14:08 GMT
需和Last-Modified结合使用。用于控制请求文件的有效时间,当请求数据在有效期内时客 户端浏览器从缓存请求数据而不是服务器端. 当缓存中数据失效或过期,才决定从服务器更新数据。
4、Last-Modified和Expires
Last- Modified标识能够节省一点带宽,但是还是逃不掉发一个HTTP请求出去,而且要和Expires一起用。而Expires标识却使得浏览器干脆连 HTTP请求都不用发,比如当用户F5或者点击Refresh按钮的时候就算对于有Expires的URI,一样也会发一个HTTP请求出去,所 以,Last-Modified还是要用的,而 且要和Expires一起用。
5、 Etag和Expires
如果服务器端同时设置了 Etag和Expires 时,Etag原理同样,即与Last-Modified/Etag对应的HttpRequest Header:If-Modified-Since和If-None-Match。我们可以看到这两个Header的值和WebServer发出的 Last-Modified,Etag值完全一样;在完全匹配If-Modified-Since和If-None-Match即检查完修改时间和 Etag之后,服务器才能返回304.
6、Last-Modified和Etag
Last-Modified 和ETags请求的http报头一起使用,服务器首先产生 Last-Modified/Etag标记,服务器可在稍后使用它来判断页面是否已经被修改,来决定文件是否继续缓存
过程如下:
1. 客户端请求一个页面(A)。
2. 服务器返回页面A,并在给A加上一个Last-Modified/ETag。
3. 客户端展现该页面,并将页面连同Last-Modified/ETag一起缓存。
4. 客户再次请求页面A,并将上次请求时服务器返回的Last-Modified/ETag一起传递给服务器。
5. 服务器检查该Last-Modified或ETag,并判断出该页面自上次客户端请求之后还未被修改,直接返回响应304和一个空的响应体。
注:
1、Last- Modified和Etag头都是由Web Server发出的Http Reponse Header,Web Server应该同时支持这两种头。
2、Web Server发送完Last-Modified/Etag头给客户端后,客户端会缓存这些头;
3、客户端再次发起相同页面的请求时,将分别发送与Last-Modified/Etag对应的Http RequestHeader:If-Modified-Since和If-None-Match。我们可以看到这两个Header的值和 WebServer发出的Last-Modified,Etag值完全一样;
4、 通过上述值到服务器端检查,判断文件是否继续缓存;


二、Apache、 Lighttpd和Nginx中针配置Etag和Expires,有效缓存纯静态如css/js/pic/页面/流媒体等文件。
A、Expires
A.1、 Apache Etag
使用Apache的mod_expires 模块来设置,这包括控制应答时的Expires头内容和Cache-Control头的max-age指令
ExpiresActive On
ExpiresByType image/gif "access plus 1 month"
ExpiresByType image/jpg "access plus 1 month"
ExpiresByType image/jpeg "access plus 1 month"
ExpiresByType image/x-icon "access plus 1 month"
ExpiresByType image/bmp "access plus 1 month"
ExpiresByType image/png "access plus 1 month"
ExpiresByType text/html "access plus 30 minutes"
ExpiresByType text/css  "access plus 30 minutes"
ExpiresByType text/txt  "access plus 30 minutes"
ExpiresByType text/js   "access plus 30 minutes"
ExpiresByType application/x-javascript   "access plus 30 minutes"
ExpiresByType application/x-shockwave-flash     "access plus 30 minutes"或
<ifmodule mod_expires.c>
<filesmatch "\.(jpg|gif|png|css|js)$">
ExpiresActive on
ExpiresDefault "access plus 1 year"
</filesmatch>
</ifmodule>当设置了expires后,会自动输出Cache-Control 的max-age 信息
具体关于 Expires 详细内容可以查看Apache官方文档。
在这个时间段里,该文件的请求都将直接通过缓存服务器获取,
当然如果需要忽略浏览器的刷新请求(F5),缓存服务器squid还需要使用 refresh_pattern 选项来忽略该请求
refresh_pattern -i \.gif$ 1440 100% 28800 ignore-reload
refresh_pattern -i \.jpg$ 1440 100% 28800 ignore-reload
refresh_pattern -i \.jpeg$ 1440 100% 28800 ignore-reload
refresh_pattern -i \.png$ 1440 100% 28800 ignore-reload
refresh_pattern -i \.bmp$ 1440 100% 28800 ignore-reload
refresh_pattern -i \.htm$ 60 100% 100 ignore-reload
refresh_pattern -i \.html$ 1440 50% 28800 ignore-reload
refresh_pattern -i \.xml$ 1440 50% 28800 ignore-reload
refresh_pattern -i \.txt$ 1440 50% 28800 ignore-reload
refresh_pattern -i \.css$ 1440 50% 28800 reload-into-ims
refresh_pattern -i \.js$ 60 50% 100 reload-into-ims
refresh_pattern . 10 50% 60有关Squid中Expires的说明,请参考Squid官方中refresh_pattern介 绍。
A.2、Lighttpd Expires
和Apache一样Lighttpd设置expire也要先查看是否支持了mod_expire模 块,
下面的设置是让URI中所有images目录下的文件1小时后过期;
expire.url = ( "/images/" => "access 1 hours" )下面是让作用于images目录及其子目录的文件;
$HTTP["url"] =~ "^/images/" {
 
expire.url = ( "" => "access 1 hours" )
 
}也可以指定文件的类型;
$HTTP["url"] =~ "\.(jpg|gif|png|css|js)$" {
 
expire.url = ( "" => "access 1 hours" )
 
}具体参考Lighttpd官方Expires解释
A.3、Nginx中Expireslocation ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$
{
expires 30d;
}
location ~ .*\.(js|css)?$
{
expires 1h;
} 这类文件并不常修改,通过 expires 指令来控制其在浏览器的缓存,以减少不必要的请求。 expires 指令可以控制 HTTP 应答中的” Expires “和” Cache-Control “的头标(起到控制页面缓存的作用)。其他请参考Nginx中Expires
B.1、Apache中Etag设置在Apache中设置Etag的支持比较简单,只用在含有静态文件的目录中建立一个文件.htaccess, 里面加入:
FileETag MTime Size这样就行了,详细的可以参考Apache的FileEtag文档页
B.2、 Lighttpd Etag在Lighttpd中设置Etag支持:
etag.use-inode: 是否使用inode作为Etag
etag.use-mtime: 是否使用文件修改时间作为Etag
etag.use-size: 是否使用文件大小作为Etag
static-file.etags: 是否启用Etag的功能
第四个参数肯定是要enable的, 前面三个就看实际的需要来选吧,推荐使用修改时间
B.3、 Nginx Etag
Nginx中默认没有添加对Etag标识.Igor Sysoev的观点”在对静态文件处理上看不出如何Etag好于Last-Modified标识。”
Note:
Yes, it's addition,and it's easy to add, however, I do not see howETag is better than Last-Modified for static files. -Igor Sysoev
A nice short description is here:
http://www.mnot.net/cache_docs/#WORK
It looks to me that it makes some caches out there to cache theresponse from the origin server more reliable as in rfc2616(ftp://ftp.rfc-editor.org/in-notes/rfc2616.txt) is written.3.11 Entity Tags 13.3.2 Entity Tag Cache Validators 14.19 ETag
当然也有第三方nginx- static-etags 模块了,请参考
https://github.com/mikewest/nginx-static-etags
三、对于非实时交互动态页面中Expires和Etag处理
对数据更新并不频繁、如tag分类归档等等,可以考虑对其cache。简单点就是在非实时交互的动 态程序中输出expires和etag标识,让其缓存。但需要注意关闭session,防止http response时http header包含session id标识;
3.1、Expires
如expires.php
<?php
 
header('Cache-Control: max-age=86400,must-revalidate');
 
header('Last-Modified: ' .gmdate('D, d M Y H:i:s') . ' GMT' );
 
header("Expires: " .gmdate ('D, d M Y H:i:s', time() + '86400′ ). ' GMT');
 
?>以上信息表示该文件自请求后24小时后过期。
其他需要处理的动态页面直接调用即可。
3.2、Etag
根据Http返回状态来处理。当返回304直接从缓 存中读取
如etag.php
>
cache();
echo date("Y-m-d H:i:s");
function cache()
{
$etag = "http://xok.la";
if ($_SERVER['HTTP_IF_NONE_MATCH'] == $etag)
{
header('Etag:'.$etag,true,304);
exit;
}
else header('Etag:'.$etag);
}
?>


  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值