在一个应用程序中,出于历史原因,一些公共图像资源被符号链接到替代名称。例如,我们可能有
a.png
b.png -> a.png
Google的PageSpeed Insight应该从一致的URL提供相同的内容,这适用于此类资产以及内容。我没有重新组织我们拥有的资产,而是希望让Apache执行从b.png到a.png的外部重定向。
使用mod_rewrite,我可以让RewriteCond缩小符号链接:
' - l'(是符号链接) 将TestString视为路径名并测试它是否存在,并且是一个符号链接。
但是如何获得符号链接的扩展路径?我需要它部分地确保目标在web范围内,部分是为了执行重定向。
答案 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
...测试,检查您的日志文件,调整,冲洗并重复...
完成后,不要忘记从配置中删除RewriteLog
和RewriteLogLevel
指令,因为它们会减慢apache的速度。
/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_
。
现在它应该确保所请求的文件和链接目标都在同一目录中。