2

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

a.png
b.png -> a.png

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

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

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

但是我怎样才能得到符号链接的扩展路径呢?我需要它部分是为了确保目标在网络范围内,部分是为了执行重定向。

4

2 回答 2

3

(这里的第一篇文章)

我一直在寻找类似问题的解决方案。这是可能的,但没有简单的答案。我必须混合来自多个 Google 搜索的信息才能使其正常工作。

首先,关于符号链接(wiki)的注释:

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

因此,除非 apache 开发人员添加特定选项来处理符号链接(如-l您提到的),否则我们必须依靠另一种方法来正确解决它们。

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

所以,我们开始吧。以 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>否则不会处于活动状态,即使您后来在比赛中将其设置为!注意所有这些特性并仔细阅读您的日志文件,否则您可能会浪费几个小时的时间来敲墙,想知道为什么它说“地图查找失败”。RewriteEngineon <VirtualHost>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

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

完成后,不要忘记从配置中删除RewriteLogandRewriteLogLevel指令,因为它们会大大降低 apache 的速度。


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

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

于 2014-01-08T18:24:29.880 回答
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_为您喜欢的路径。现在它应该确保请求的文件和链接目标都在同一个目录中。

于 2014-09-28T22:20:50.297 回答