Apache基于符号链接重定向

时间:2013-05-03 03:46:16

标签: apache mod-rewrite

在一个应用程序中,出于历史原因,一些公共图像资源被符号链接到替代名称。例如,我们可能有

a.png
b.png -> a.png

Google的PageSpeed Insight应该从一致的URL提供相同的内容,这适用于此类资产以及内容。我没有重新组织我们拥有的资产,而是希望让Apache执行从b.png到a.png的外部重定向。

使用mod_rewrite,我可以让RewriteCond缩小符号链接:

  

' - l'(是符号链接)   将TestString视为路径名并测试它是否存在,并且是一个符号链接。

但是如何获得符号链接的扩展路径?我需要它部分地确保目标在web范围内,部分是为了执行重定向。

2 个答案:

答案 0 :(得分:3)

(这里的第一篇文章)

我一直在寻找类似问题的解决方案。这是可能的,但没有简单的答案。我不得不混合来自多个Google搜索的信息,以使其有效。

首先,关于符号链接(wiki)的说明:

  

符号链接由文件系统自动解析。任何   软件程序在访问符号链接时将看到目标   相反,程序是否知道符号链接。

所以,除非apache devs添加特定的选项来处理符号链接(比如你提到的-l),否则我们必须依靠另一种方法来正确解决它们。

mod_rewrite具有RewriteMap配置选项。有了它,您可以使用不同类型的外部资源来执行重写,例如文本文件或数据库查询。它还可以调用外部程序,例如......符号链接解析器,例如:)

所以,我们走了。以root身份运行以下所有命令并适应您的系统设置(这适用于Debian)。

<小时/> 首先,如果我们使用RewriteMap选项,我们还需要RewriteLock选项来防止竞争条件。 RewriteLock选项不能位于<VirtualHost><Directory>上下文中。它必须在全局上下文中,因此我将其添加到新的rewrite.conf中并重新加载模块。 运行以下命令:

lock=/var/lock/apache2/rewrite_lock
touch $lock
chown www-data:www-data $lock
echo "RewriteLock $lock" >> /etc/apache2/mods-available/rewrite.conf
a2dismod rewrite
a2enmod rewrite

接下来,创建/usr/local/bin/resolve-symlink并添加以下代码:

#!/bin/sh
while read line
do
    echo `readlink "$line"`
done

使其可执行并将其测试为apache:

chmod +x /usr/local/bin/resolve-symlink
su - www-data
/usr/local/bin/resolve-symlink

脚本应该等待您的输入,然后返回空行或给定符号链接的目标。使用CTRL+C退出。示例(>是STDIN,<是STDOUT):

> test
<
> /bin/sh
< bash
> /bin/bash
<

test不存在,因此返回一个空行。 /bin/sh是一个符号链接,脚本将其解析为bash。最后,/bin/bash是一个文件而不是链接,因此是另一个空行。

现在,在<VirtualHost>配置中,添加以下行:

RewriteEngine On
RewriteMap symlink prg:/usr/local/bin/resolve-symlink
RewriteLog /var/log/apache2/rewrite.log
RewriteLogLevel 9

RewriteMap不能位于<Directory>上下文中,除非RewriteEngine也设置为on <VirtualHost>,否则不会处于有效状态}} context ,即使您稍后在on比赛中将其设置为<Directory>!注意所有这些特点并仔细阅读你的日志文件,否则你可能会在墙上敲打几个小时,想知道为什么它会说“地图查找失败”。

最后,重写,无论你喜欢什么语境:

RewriteCond %{REQUEST_FILENAME} -l
RewriteCond ${symlink:%{REQUEST_FILENAME}} ^(.+)$
RewriteRule $ ${REQUEST_SCHEME}://${HTTP_HOST}/%1 [R,L]

第一行检测符号链接,第二行检测结果并检查结果是否为空,第三行重写URL(%1是映射的结果)并向浏览器发送302重定向。您可能需要END标志而不是L标志。

现在重启apache ......

service apache2 restart

...测试,检查您的日志文件,调整,冲洗并重复...

完成后,不要忘记从配置中删除RewriteLogRewriteLogLevel指令,因为它们会减慢apache的速度。

<小时/> 重要提示。在我的例子中,符号链接都指向同一文件夹中的文件,因此URL重写更容易一些。如果您的符号链接指向子目录,甚至指向文件系统上的其他位置,您将不得不修改脚本和配置来解决它,但即使这样,它也可能无法按预期工作,因为apache并不总是能够找出要发送到浏览器的正确URL。例如,如果你有一个符号链接,比方说/usr/share/apache2/icons/apache_pb.png,apache可能会重定向到http://example.com/usr/share/apache2/icons/apache_pb.png,当然,它不存在......

另外,我会添加一些信息链接,但我只限于2 ...无论如何,快乐的调试!

答案 1 :(得分:0)

我已经获得了有关此主题的更多信息。它已经运行了很长一段时间,我对文件/usr/local/bin/resolve-symlinks进行了以下修改:

#!/bin/bash

BASE=_ALL_YOUR_BASE_ARE_BELONG_TO_US_
BASE_LEN=${#BASE}

while read FILE
do
    # $FILE must be in $BASE
    if [[ $BASE != ${FILE:0:$BASE_LEN} ]]
    then
            echo
            continue
    fi
    REL_FILE=${FILE:$BASE_LEN}
#       echo $REL_FILE

    # $LINK must also be in $BASE
    LINK=$(readlink -f $FILE)
    if [[ $BASE != ${LINK:0:$BASE_LEN} ]]
    then
            echo
            continue
    fi
    REL_LINK=${LINK:$BASE_LEN}
#       echo $REL_LINK

    # $REL_FILE and $REL_LINK must be different
    if [[ $(basename $REL_FILE) == $(basename $REL_LINK) ]]
    then
            echo
            continue;
    fi

    # success!
    echo $REL_LINK
done

当然,用您最喜欢的路径替换_ALL_YOUR_BASE_ARE_BELONG_TO_US_。 现在它应该确保所请求的文件和链接目标都在同一目录中。