RewriteCond 文件存在检查因文件已存在而失败

RewriteCond 文件存在检查因文件已存在而失败

我对这个重写规则有一个奇怪的情况:

RewriteCond img/$2/$3/$4/$1 -f
RewriteRule ^img/(([a-z0-9]{4})([a-z0-9]{4})([a-z0-9]{4})[a-z0-9]{28}\.\w+)$ img/$2/$3/$4/$1 [L]

其目录结构如下(简化):

var/
  images/
    ..
  www/
    .htaccess
    img -> /var/images

换句话说,图像存储在 webroot 之外的通用数据存储区域中,并img通过符号链接链接到 webroot 的目录中。图像名称是哈希值。为了提高效率,它们存储在三级深层目录层次结构中。例如:

0a808e34edaaeeffd973e4138789a4957d6b6a26.jpg

存储在

images/0a80/8e34/edaa/0a808e34edaaeeffd973e4138789a4957d6b6a26.jpg

重写规则只是将文件名重写到嵌套目录结构中。

现在,奇怪的是,RewriteCond在我的本地系统上运行良好,但在测试服务器上却失败了。Apache 调试日志明确指出,-f这种情况下的“模式不匹配”​​。如果我简单地删除这个条件,重写规则就可以正常工作,并且可以提供图像。

什么可能导致-f明明存在的文件失败?

FollowSymLinks是允许的。Apache 版本 2.2.22-6ubuntu2 通过 apt 安装,几乎没有修改。在本地安装的 Apache 2.2.23 上工作(通过 homebrew)。没有看到任何显著的变化这两个版本之间应该会导致这种情况。


关于实际目录结构的一些可能更重要的细节:

$ ls -l /var/www/myapp/current
[snip] /var/www/myapp/current -> /var/www/myapp/releases/20130418090750

$ ls -la /var/www/myapp/current/webroot
[snip]
[snip] .htaccess
[snip] img -> /usr/local/var/myapp/images

Apache webroot 配置为:

DocumentRoot /var/www/myapp/current/webroot

如果我将其写RewriteCond为:

RewriteCond /usr/local/var/myapp/images/$2/$3/$4/$1 -f

它可以工作。但如果可以避免的话,我宁愿不硬编码绝对路径。

Apache 是否会对多个级别的符号链接感到困惑?

答案1

实际上,我还没有看到过一篇文章有​​关于RewriteCond从下面获取变量的教程。但是,您仍然可以尝试在顶部RewriteRule添加一个指令RewriteBase.htaccess文件:

RewriteBase /www/

或者这样,都尝试一下:

RewriteBase /var/www/

或者你可以尝试下面这些指令集之一,但是排除上面列出的任何RewriteBase指令:

RewriteCond /www/img/$2/$3/$4/$1 -f
RewriteRule ^www/img/(([a-z0-9]{4})([a-z0-9]{4})([a-z0-9]{4})[a-z0-9]{28}\.\w+)$ /www/img/$2/$3/$4/$1 [L]

或者你甚至可以尝试一下:

RewriteCond /var/www/img/$2/$3/$4/$1 -f
RewriteRule ^var/www/img/(([a-z0-9]{4})([a-z0-9]{4})([a-z0-9]{4})[a-z0-9]{28}\.\w+)$ /var/www/img/$2/$3/$4/$1 [L]

很抱歉抄袭了你的重写条件和规则的格式,因为你说过“它在您的本地开发系统上运行。”但如果你只是想重写,这是我向你推荐的简单规则/$var1.$var2进入/图像/0a80/8e34/edaa/$var1.$var2,你甚至可以逐个静态添加其他内容:

RewriteRule ^([a-zA-Z0-9_-]+).([a-zA-Z]{3})$ /images/0a80/8e34/edaa/$var1.$var2

或者如果你想重写,你甚至可以尝试这个/img/0a808e34edaaeeffd973e4138789a4957d6b6a26.jpg动态地进入/img/0a80/8e34/edaa/0a808e34edaaeeffd973e4138789a4957d6b6a26.jpg如果重新映射的动态 URL 是一个文件,则条件是:

RewriteCond /img/$2/$3/$4/$1\.$5 -f
RewriteRule ^img/(([a-z0-9]{4})([a-z0-9]{4})([a-z0-9]{4})[a-z0-9]{28})\.([a-z]{3})$ /img/$2/$3/$4/$1.$5

请记住“0a80”“8e34”“埃达”必须精确到 4 和字符。“eeffd973e4138789a4957d6b6a26”必须是 28 并且“jpg”必须是 3。我希望这会起作用,但我怀疑..

答案2

如果它在 localhost 上运行良好,但在 test.com 上却不行,我猜是文件系统出了问题,或者与您可能认为理所当然的更一般的站点配置有关。您是否安装了两个操作系统,然后在两台机器上使用相同的过程安装了相同的软件包?每个 Apache 附带的默认配置是什么样的?在您查看之前修改了默认配置的软件包怎么样?

也许您的 Apache 版本非常相似,但如果它们来自不同的来源,默认配置可能有所不同,并且随后可能会进行不同的修改。从顶部开始验证您的配置。有什么不同?尝试使它们看起来完全相同(不仅是您的重写,还包括虚拟主机或服务器上下文。)

您的 Rewrite 指令的上下文可能会有所帮助(因为我认为这是范围问题)。重写是在 VirtualHost、Document-Root 还是 Directory 上下文中?

我从你的帖子中看到的成功与失败之间的最大区别是:

相对的

RewriteCond img/$2/$3/$4/$1 -f

绝对

RewriteCond /usr/local/var/myapp/images/$2/$3/$4/$1 -f

Apache 能够找到该文件,因此不应该是权限问题或类似问题。您是否使用了任何 Alias 指令(localhost 与 test.com)?如果没有,也许您应该尝试专门为此设置 Alias:

/var/www/myapp/当前-> /var/www/myapp/releases/20130418090750

在根配置中放置至少一个不需要符号链接的硬路径。您可以在目录上下文中完成重写...

<Directory /var/www/myapp/current/webroot>
    rewrite statements...
</Directory>

如果您在 test.com 上维护损坏的配置,但目前有符号链接,请尝试从根目录开始(临时)复制实际目录。只需验证没有浮动的松散符号链接设置。删除尽可能多的符号链接,然后逐个将其放回。

答案3

反向引用是“up”(rewriteCond)到“down”(RewriteRule)。在您发布的示例中,就像是“down”到“up”。并且,反向引用是用%表示的,而不是用$表示。

RewriteCond 反向引用:这些是形式为 %N(0 <= N <= 9)的反向引用。%1 到 %9 提供对模式的分组部分(同样在括号中)的访问,从当前条件集中最后匹配的 RewriteCond 开始。%0 提供对该模式匹配的整个字符串的访问。

你可以尝试这个:

RewriteBase /
RewriteCond %{REQUEST_URI} /img/([a-z0-9]{4})([a-z0-9]{4})([a-z0-9]{4})([a-z0-9]{28}\.\w+)$
RewriteCond %{DOCUMENT_ROOT}/test/%1/%2/%3/%4 -f
RewriteRule .* img/%1/%2/%3/%4 [L]

首先使用正则表达式查找变量。构造包含变量的文件的路径,并验证文件是否存在

我用%{文档根目录}用于在本地服务器上进行测试。如果您没有在同一个 DocumentRoot 中保存此图像文件,则需要完整路径喜欢:

RewriteCond /var/www/cache_images/test/%1/%2/%3/%4 -f

相关内容