利用客户端缓存优化服务器带宽

最近看了《构建高性能WEB站点》,非常有启发。于是立即着手开始改进Share站。

当然了,里面对现在的我来说最实用的的就是如何让动态脚本利用客户端缓冲的部分了(原书第6章内容),现在主要的改进方案也是依据与此章的内容。

首先先说下Share.popgo.org 站现在的缓冲策略:

Share站主要采用的是XML+XSLT缓冲,其中XSLT为静态文件,由Nginx服务器端设置了Cache-Control:Max-age缓冲,缓冲时间为284400秒,相当长的时间了。

然后XML文件是服务器端通过静态文件缓冲,然后由PHP程序调用生成的,其缓冲策略为:

如果有客户提交新的种子或者编辑现有的种子,那么立即刷新缓冲;
如果在设定的时间段内没有刷新过缓冲,那么强制刷新,刷新的时间可以在后台指定。

刷新的时间判断由PHP来读取文件的最后修改时间来实现。

虽然XML是静态文件在服务器上,但是每次调用的是PHP,Nginx服务器把它认为是动态脚本,是不允许客户端进行缓冲的。现在我需要调整的就是让客户端也可以动态的缓冲这个XML文件,不用我每次都去读取和判断这个XML文件。最好是能够在我加载处理缓冲这几个类文件之前就做这个操作,也节约很多PHP程序处理的时间。

改起来就相当的简单了,首先先在所有的输出的地方加上:

header("Last-Modified: ".gmdate ("D, d M Y H:i:s", time())." GMT");


然后在开头的地方加上

$modified_time = $_SERVER['HTTP_IF_MODIFIED_SINCE'];


if(strtotime($modified_time) && strtotime($modified_time) > time() - $getnewindex )//如果没有过期
{
    header("HTTP/1.1 304 Not Modified");
    exit;
}

就应该可以了……然后我满怀希望的打开FF+Firebug。结果发现在网络窗口中,依然每次返回的都是200而不是预想中的304……

到底出了什么问题?

仔细查看浏览器的Header,我发现浏览器中多了两个Header:

Cache-Control:no-cache;
Pragma:no-cache;

这个应该就是罪魁祸首了,大概是Nginx自己给出的一些默认的Header干扰了我设置的Last-Modified,于是继续修改程序,考虑到本身我就设置了以$getnewindex为参数的缓冲时间,那我还不如自己给浏览器提醒这个东西过期的时间是$getnewindex,避免它每次都还要找我来询问是否过期好了,如果这个时间出现了其他的提交,我觉得也无所谓了,不差那么点时间,毕竟大家对这个种子的出现也不是像开彩票那样的关心时间点。

于是在所有的输出前加入:

header("Last-Modified: ".gmdate ("D, d M Y H:i:s", filemtime($filename))." GMT");
header("Cache-Control:max-age=".$getnewindex."");
header("Pragma: ");
强制的覆盖掉Nginx的Header,这下就完美了吧……

结果发现还是不对……第一次是200,然后接着就是304,然后第三次刷新就又出现了200……如此的反复出现,难道Header还有地方没给全?嗯……应该是第二次接受的时候Nginx又很不老实的给我吧Cache-Control给加上去了……于是也修改上面的程序:


$modified_time = $_SERVER['HTTP_IF_MODIFIED_SINCE'];

if(strtotime($modified_time) && strtotime($modified_time) > time() - $getnewindex )
{
    header("Cache-Control:max-age=".$getnewindex."");
    header("Pragma: ");
    header("HTTP/1.1 304 Not Modified");
    exit;
}

这下就大功告成了……

以前每次需要下载54KB的数据,现在如果不点击刷新按钮,那么1B都不用下载,如果点击刷新但是没有更改,那么只需要下载150B的HTTP头文件。消耗时间由原本的1.2秒提升到现在的0.3秒左右(304的时候)或者更小(在max-age时间内是不请求服务器的,完全依赖于客户端本机的速度)

同时发现了一点小奇怪的地方:

IE和FF的表现基本上是相同的:
如果通过页面点击或者在浏览器地址栏上回车,那么会响应max-age的参数,在缓冲有效的时间段内不发送任何请求。
如果通过刷新按钮或者F5,那么会无视掉max-age,发送一个request,然后如果客户端返回304 Not modified,那么读本机缓冲。
如果按Ctrl+F5强制刷新,那么直接会将last-modified时间置为空,然后强制获取新内容

但是Chrome有点不同,它的不同之处就在于,在浏览器地址栏上回车对它来说等同于F5,也即是这个时候它会无视掉max-age的参数值,直接发送request,只有在页面互相跳转的时候它会用到那个max-age值不予发送请求。


评论

此博客中的热门博文

远程记录OpenWRT日志

用OpenWRT打造自动翻墙路由器(详解篇)

Python中为什么要用is None来代替== None?