客户的要求,还剩下最后一步,就是referer限定。对于apache,有Mod_rewrite现成的可用:

RewriteEngine on
RewriteCond %{HTTP_REFERER} !^http://(www.)?test.com/.*$ [NC]
RewriteRule .mp3$ http://www.test.com/ [R=301,L]

不过既然之前已经用了perl,这里就一口气把perl写完吧:

sub handler {
    my $r = shift;
    my $s = Apache2::ServerUtil->server;
    my $secret = $r->dir_config('Secret') || '';#这里可以写成$r->dir_config->{Secret}
    my $uri = $r->uri() || '';
    my $expire = 2 * 3600;
+    my $referer = $r->headers_in->{Referer} || '';#这里却不可以写成$r->headers_in(Referer),会报错“argument is not a blessed reference (expecting an APR::Table derived object),不知道为什么?
+    if ($referer =~ m#^http://music.test.com#oi){
    if ($uri =~ m#^/(d{4})(d{2})(d{2})(d{2})(d{2})/(w{32})(/S+.mp3)$#oi){
        my ($year, $mon, $mday, $hour, $min, $md5, $path) = ($1, $2, $3, $4, $5, $6, $7);
        my $str = md5_hex($secret . $year . $mon . $mday . $hour . $min . $path);
        my $reqtime = mktime(00, $min, $hour, $mday, $mon - 1, $year - 1900);
        my $now = time;
        if ( $now - $reqtime < $expire){
                if ($str eq $md5) {
                    $r->uri("$path");
                    return Apache2::Const::DECLINED;
                }
        }
   }
+}
}

简单两句话,就ok了。测试如下: [27/May/2010:22:45:00 +0800] "GET /201005272218/ceaf967f6bcf9a185a3287b2e3ff5a02/smg/123.mp3 HTTP/1.0" 200 - http://music.test.com "Wget/1.10.2 (Red Hat modified)" [27/May/2010:22:45:05 +0800] "GET /201005272218/ceaf967f6bcf9a185a3287b2e3ff5a02/smg/123.mp3 HTTP/1.0" 404 - http://www.baidu.com "Wget/1.10.2 (Red Hat modified)" [27/May/2010:22:45:17 +0800] "GET /201005272218/ceaf967f6bcf9a185a3287b2e3ff5a03/smg/123.mp3 HTTP/1.0" 404 - http://music.test.com "Wget/1.10.2 (Red Hat modified)" 对于各种非正常的访问,都返回404 NOT FOUND。 如果想要返回403 ACCESS DENIED的话,经测试,在前面这些handler是没法做到的,必须在perlaccesshandler里才能return FORBIDDEN。那只能在之前的transhandler里统一改写uri成一个约定字符串,然后在access中再匹配拒绝。很麻烦。。。