芒果小站

  1. 全球最具业界良心的主机 - Linode

    毫无疑问,目前做得最好的主机供应商

    猛击这里查看

  2. 芒果小站目前使用的主机 - Linode

    客服响应快,随时退款,XEN 架构稳定

    猛击这里查看

  3. 最好的日本东京线路主机 - Linode

    可选弗里蒙特、达拉斯、亚特兰大、纽瓦克、伦敦、东京机房

    猛击这里查看

  • 1
  • 2
  • 3
切换到精简模式
5

PHP 和浏览器缓存机制

作者 芒果/分类 代码/发布于 2012-05-07 00:12

站长军团(www.adminunion.com)的服务器放置在万网,由于站点流量不断增大,每个月都收到万网的流量超标警告,性能优化就迫在眉睫了。

访问站长军团时,服务器端对每次查询都会缓存,以和减少服务端重复计算的开销、提升二次访问时的速度体验。然而我恰恰忽略了浏览器端的缓存。

浏览器的缓存策略,会暂时将浏览过的文件缓存在本地磁盘。当用户重复请求页面时,告知客户端页面并没有发生改变,可以调用缓存。 那么如何知道客户端是否有页面缓存呢?从 HTTP 协议层面来说,浏览器发送请求时会先发送如下 HTTP 头:

Connection	Keep-Alive
Date	Sun, 06 May 2012 18:00:36 GMT
Last-Modified	Sun, 06 May 2012 17:31:02 GMT
Etag	ec1f629013925ab0fa4389ba926e8c06
Keep-Alive	timeout=15, max=299
Server	Apache/2.2.16 (Unix) DAV/2
Vary	Accept-Encoding

请注意其中的这两行,描述了页面的缓存信息:

Last-Modified	Sun, 06 May 2012 17:31:02 GMT
Etag	ec1f629013925ab0fa4389ba926e8c06

这个情况下,如果服务器响应 304 状态码,浏览器会自觉地从缓存中读取数据;如果响应 200 状态码,不管有没有客户端缓存,照样从服务端读取。

按照这个理论支撑,比如站长军团大部分查询结果都是 ajax 异步获取的,二次访问就都可以通过这种方式进行缓存改造。只要客户端有缓存,就向客户端发送一个 304 响应状态码,然后退出程序执行。

浏览器发出的请求中包含 If-Modified-Since 和 If-None-Match 两个参数:

If-Modified-Since 表示询问数据的最后修改时间是否是某个时间值。然后服务器会检查数据的最后修改时间,如果是该时间则返回 304 状态码,客户端接收到该状态码后直接从本地读取缓存。这种情况有一个前置条件,即本地必须存在缓存资源,浏览器才会发送 If-Modified-Since 参数,并且值为上一次服务器返回的 Last-Modified 值。

If-None-Match 类似,它由服务器返回的 Etag 值生成,仅仅用于服务器检查数据的修改时间,可以是任意值。考虑到 If-Modified-Since 结合 Last-Modified 的方法并不被所有服务器支持,这里就只考虑使用 etag 的实现。

PHP 中通过 $_SERVER[‘HTTP_IF_NONE_MATCH’] 可以判断文件是否被浏览器缓存,代码片段如下:

//使用 etag 标记控制缓存
$etag = md5(date('Ymd'));
if ($_SERVER['HTTP_IF_NONE_MATCH'] == $etag) {
	header('Etag:' . $etag, true, 304);
	exit();
} else {
	header('Etag:' . $etag);
}

这里我使用当日日期来生成 etag,这样可以保证缓存最多生效一天时间,这个参数可以根据需要修改。

补充说明:
即便是 304 响应,实际上还是会请求服务端,因为需要建立连接来判断是否需要传输数据,304 缓存节约的是静态资源传输的开销;
另一种缓存是 200 响应时的缓存,不建立连接但请求会响应 200 状态码,并从本地直接读取缓存。

版权所有,转载请注明出处。
转载自 <a href="http://mangguo.org/php-and-the-browser-cache-mechanism/" title="PHP 和浏览器缓存机制" rel="bookmark">PHP 和浏览器缓存机制 | 芒果小站</a>
如果喜欢这篇文章,欢迎订阅芒果小站以获得最新内容。

已经有 5 条群众意见

  1. 软件盒子 /2012-05-07 14:20

    沙花,我来了,支持一下manggo 回应

    #1
  2. 芒果软件盒子/2012-05-07 14:43

    欢迎光临 回应

    #2
  3. 流水线 /2012-05-07 15:28

    技术达人 回应

    #3
  4. wisock /2012-07-20 06:30

    这个好似个好方法 回应

    #4
  5. ?
    草丁-哥侯 CaoDin.com » PHP代码片段收集 /2012-09-27 18:13

    […] PHP 和浏览器缓存机制 […] 回应

    #5

下面我简单说几句