php中缓存的一些方法

php中缓存的一些方法

缓存是好东西
当用户代理(如浏览器)向服务器请求一个资源时,第一次请求过后它就会缓存服务器的响应,以避免重复之后的相同请求。缓存时间的长短取决于两个因素:代理的配置和服务器的缓存控制header。所有浏览器都有不同的配置选项和处理方式,但大多数都会把一个资源至少缓存到会话结束(除非被明确告知)。

为了不让浏览器缓存改动频繁的页面,你很可能已经发送过header不缓存动态内容。在php中,以下两行命令可以做到:

<?php
header("Cache-Control: private");
header("Cache-Control: no-cache", false);
?>听起来太简单了?确实如此——因为有些代理(浏览器)在某些环境下将忽略这些header。要确保浏览器不缓存文档,应该更强硬一些:

<?php
# 让它在过去就“失效”
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");

# 永远是改动过的
header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT");

# HTTP/1.1
header("Cache-Control: no-store, no-cache, must-revalidate");
header("Cache-Control: post-check=0, pre-check=0", false);

# HTTP/1.0
header("Pragma: no-cache");
?>这样,对于我们不想缓存的内容来说已经行了。但对于那些不会每次请求时都有改动的内容,应该鼓励浏览器更霸道的缓存它。“If-Modified-Since”请求header能够做到这点。如果客户端在请求中发送一个“If-Modified-Since”header,apache(或其他服务器)会以状态代码304(没改过)响应,告诉浏览器缓存已经是最新的。使用这个机制,能够避免重复发送文件给浏览器,不过仍然导致了一个HTTP请求的消耗。嗯,再想想。

与If-Modified-Since机制类似的是实体标记(entity tags)。在apache环境下,每个对静态文件的响应都会发出一个“ETag”header,它包含了一个由文件修改时间、文件大小和inode号生成的校验和(checksum)。在下载文件之前,浏览器会发送一个HEAD请求去检查文件的etag。可ETag跟If-Modified-Since有同样的问题:客户端仍旧需要执行HTTP请求来验证本地缓存是否有效。

此外,如果你使用多台服务器提供内容,得小心使用if-modified-since和etags。在两台负载平衡的服务器环境下,对一个代理(浏览器)来说,一个资源可以这次从A服务器得到,下次从B服务器得到(htmlor注:lvs负载平衡系统就是个典型的例子)。这很好,也是采用平衡负载的原因。可是,如果两台服务器给同一个文件生成了不同的etag或者文件修改日期,浏览器就无所适从了(每次都会重新下载)。默认情况下,etag是由文件的inode号生成的,而多台服务器之间文件的inode号是不同的。可以使用apache的配置选项关掉它:

FileETag MTime Size使用这个选项,apache将只用文件修改日期和文件大小来决定etag。很不幸,这导致了另一个问题(一样能影响if-modified-since)。既然etag依赖于修改时间,就得让时间同步。可往多台服务器上传文件时,上传时间差个一到两秒是常有的事。这样一来,两台服务器生成的etag还是不一样。当然,我们还可以改变配置,让etag的生成只取决于文件大小,但这就意味着如果文件内容变了而大小没变,etag也不会变。这可不行。

缓存真是个好东西
看来我们正从错误的方向入手解决问题。(现在的问题是,)这些可能的缓存策略导致了一件事情反复发生,那就是:客户端向服务器查询本地缓存是否最新。假如服务器在改动文件的时候通知客户端,客户端不就知道它的缓存是最新的了(直到接到下一次通知)?可惜天公不做美——(事实)是客户端向服务器发出请求。

其实,也不尽然。在获取js或css文件之前,客户端会用<script>或<link>标记向服务器发送一个请求,说明哪个页面要加载这些文件。这时候就可以用服务器的响应来通知客户端这些文件有了改动。有点含糊,说得再详细点就是:如果改变css和js文件内容的同时,也改变它们的文件名,就可以告诉客户端对url全都永久缓存——因为每个url都是唯一的。

假如能确定一个资源永不更改,我们就可以发出一些霸气十足的缓存header(htmlor注:这句也很有气势吧)。在php里,两行就好:

<?php
header("Expires: ".gmdate("D, d M Y H:i:s", time()+315360000)." GMT");
header("Cache-Control: max-age=315360000");
?>我们告诉浏览器这个内容在10年后(10年大概会有315,360,000秒,或多或少)过期,浏览器将会保留它10年。
如履薄冰

头几天在网上看到张孝祥写的关于缓存的文章,是理论方面的,很深奥.不过很不错.

http://blog.csdn.net/zhangxiaoxi ... 6/05/14/727904.aspx