您当前的位置:中客资源站网络学院Java编程Java技巧 → 文章内容 退出登录 用户管理
本类热门文章
相关下载
让javascript跑得更快
作者:本站  来源:本站整理  发布时间:2007-4-30 5:51:46

减小字体 增大字体

6;2 [L]

这条规则匹配任何带有指定扩展名同时含有“版本”信息(version nugget)的url,它会把这些url重定向到一个不含版本信息的路径。如下所示:

URL Path/images/foo.v2.gif -> /images/foo.gif/css/main.v1.27.css -> /css/main.css/javascript/md5.v6.js -> /javascript/md5.js

使用这条规则,就可以做到不改变文件路径而更改url(因为版本号变了)。由于url变了,浏览器就认为它是另一个资源(会重新下载)。想更进一步的话,可以把我们之前说的脚本编组函数结合起来,根据需要生成一个带有版本号的<script>标记列表。
说到这里,你可能会问我,为什么不在url结尾加一个查询字符串(query string)呢(如/css/main.css?v=4)?根据HTTP缓存规格书所说,用户代理对含有查询字符串的url永不缓存。虽然ie跟 firefox忽略了这点,opera和safari却没有——为了确保所有浏览器都缓存你的资源,还是不要在url里用查询字符串的好。
现在不移动文件就能更改url了,如果能让url自动更新就更好了。在小型的产品环境下(如果有大型的产品环境,就是开发环境了),使用模板功能可以很轻易的实现这点。这里用的是smarty,用其他模板引擎也行。

SMARTY:
<link xhref="{version xsrc='/css/group.css'}" rel="stylesheet" type="text/css" />

PHP:
function smarty_version($args){
$stat = stat($GLOBALS['config']['site_root'].$args['src']);
$version = $stat['mtime'];
echo preg_replace('!.([a-z]+?)$!', ".v$version.$1", $args['src']);
}

OUTPUT:
<link xhref="/css/group.v1234567890.css" mce_href="/css/group.v1234567890.css" rel="stylesheet" type="text/css" />

对每个链接到的资源文件,我们得到它在磁盘上的路径,检查它的mtime(文件最后修改的日期和时间),然后把这个时间当作版本号插入到url中。对于低流量的站点(它们的stat操作开销不大)或者开发环境来说,这个方案不错,但对于高容量的环境就不适用了——因为每次stat操作都要磁盘读取(导致服务器负载升高)。
解决方案相当简单。在大型系统中每个资源都已经有了一个版本号,就是版本控制的修订号(你们应该使用了版本控制,对吧?)。当我们建立站点准备部署的时候,可以轻易的查到每个文件的修订号,写在一个静态配置文件里。

<?php
$GLOBALS['config']['resource_versions'] = array( '/images/foo.gif' => '2.1', '/css/main.css' => '1.27', '/javascript/md5.js' => '6.1.4',);
?>

当我们发布产品时,可以修改模板函数来使用版本号。

<?php
function smarty_version($args){
if ($GLOBALS['config']['is_dev_site']){
$stat = stat($GLOBALS['config']['site_root'].$args['src']);
$version = $stat['mtime'];
}else{
$version = $GLOBALS['config']['resource_versions'][$args['src']];
}
echo preg_replace('!.([a-z]+?)$!', ".v$version.$1", $args['src']);}
?>

就这样,不需要改文件名,也不需要记住改了哪些文件——当文件有新版本发布时它的url就会自动更新——有意思吧?我们就快搞定了。
只欠东风

之前谈到为静态文件发送超长周期(very-long-period)的缓存header时曾说过,如果不用php输出,就不能轻易的发送缓存header。很显然,有两个办法可以解决:用php输出,或者让apache来做。
php出马,手到擒来。我们要做的仅仅是改变rewrite规则,把静态文件指向php脚本,用php在输出文件内容之前发送header。

Apache:
RewriteRule ^/(.*.)v[0-9.]+.(css|js|gif|png|jpg)$ /redir.php?path=$1$2 [L]

PHP:
header("Expires: ".gmdate("D, d M Y H:i:s", time()+315360000)." GMT");
header("Cache-Control: max-age=315360000");# 忽略带有“..”的路径
if (preg_match('!..!', $_GET[path])){ go_404(); }# 保证路径开头是确定的目录
if (!preg_match('!^(javascript|css|images)!', $_GET[path])){ go_404(); }# 文件不存在?
if (!file_exists($_GET[path])){ go_404(); }# 发出一个文件类型
header$ext = array_pop(explode('.', $_GET[path]));
switch ($ext){
case 'css':
header("Content-type: text/css");
break;
case 'js' :
header("Content-type: text/javascript");
break;
case 'gif':
header("Content-type: image/gif");
break;
case 'jpg':
header("Content-type: image/jpeg");
break;
case 'png':
header("Content-type: image/png");
break;
default: header("Content-type: text/plain");
}
# 输出文件内容
echo implode('', file($_GET[path]));
function go_404(){
header("HTTP/1.0 404 File not found");
exit;
}

这个方案有效,但并不出色。(因为)跟apache相比,php需要更多内存和执行时间。另外,我们还得小心防止可能由path参数传递伪造值引起的 exploits。为避免这些问题,应该用apache直接发送header。rewrite规则语句允许当规则匹配时设置环境变量(environment variable),当给定的环境变量设置后,Header命令就可以添加header。结合以下两条语句,我们就把rewrite规则和header设置绑定在了一起:

RewriteEngine onRewriteRule ^/(.*.)v[0-9.]+.(css|js|gif|png|jpg)$ /$1$2 [L,E=VERSIONED_FILE:1]
Header add "Expires" "Mon, 28 Jul 2014 23:30:00 GMT" env=VERSIONED_FILEHeader add "Cache-Control" "max-age=315360000" env=VERSIONED_FILE
考虑到apache的执行顺序,应该把rewrite规则加在主配置文件(httpd.conf)而不是目录配置文件(.htaccess)中。否则在环境变量设置之前, header行会先执行(就那没意义了)。至于header行,则可以放在两文件任何一个当中,没什么区别。
眼观六路

(htmlor注:多谢tchaikov告知“skinning rabbits”的含义,但我不想翻的太正式,眼下的这个应该不算太离谱吧。)
通过结合使用以上技术,我们可以建立一个灵活的开发环境和一个快速又高性能的产品环境。当然,这离终极目标“速度”还有一段距离。有许多更深层的技术(比如分离伺服静态内容,用多域名提升并发量等)值得我们关注,包括与我们谈到的方法(建立apache过滤器,修改资源url,加上版本信息)殊途同归的其他路子。你可以留下评论,告诉我们那些你正在使用的卓有成效的技术和方法。

上一页  [1] [2] [3] [4] 

[] [返回上一页] [打 印]
文章评论 (评论内容只代表网友观点,与本站立场无关!)

用户名: 查看更多评论

分 值:100分 85分 70分 55分 40分 25分 10分 0分

内 容:

         (注“”为必填内容。) 验证码: 验证码,看不清楚?请点击刷新验证码