我无法理解为什么重定向依赖于RewriteRule(而不是RewriteCond)。
我的.htaccess:
Options +FollowSymLinks +SymLinksIfOwnerMatch
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^(.*)$ true.txt
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ false.txt
</IfModule>
根文件夹包含:
true.txt(包含'true')
false.txt(包含'false')
test.txt(包含'test')
如果我尝试打开test.txt
,我会true
,如果我尝试打开nonexist.txt
,我也会获得true
。
现在我改变了我的.htaccess:
...
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^(.*)$ $1
...
现在,如果我尝试打开test.txt
,我会test
,如果我尝试打开nonexist.txt
,我会false
。
更新:感谢您的回答,我了解它的工作原理,但仍然存在一个问题。
如果我尝试在另一个目录中检查'if file exists',它总是返回false
。
/files/test.txt
/script/.htaccess
/script/false.txt
/script/true.txt
现在我的.htaccess看起来像
RewriteCond %{REQUEST_FILENAME} .*(true|false).*$
RewriteRule .* - [S=2]
RewriteCond %{DOCUMENT_ROOT}/files/%{REQUEST_FILENAME} -f
RewriteRule ^(.*)$ true.txt [L]
RewriteCond %{DOCUMENT_ROOT}/files/%{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ false.txt [L]
我总是得到false
。
我也尝试了RewriteCond ../files/%{REQUEST_FILENAME}
,并且始终获得false
结果。
如果我在test.txt
文件夹中移动script
然后更改RewriteCond %{REQUEST_FILENAME}
一切正常。
答案 0 :(得分:7)
这是因为mod_rewrite的工作方式:用户请求test.txt,mod_rewrite捕获请求并将URI重写为false.txt,然后通过发送内部请求进行第二次传递对于false.txt,它被捕获并重写为true.txt。然后进行第三次传递,捕获请求并将其重写为true.txt,但由于URI保持不变,因此不再进行传递。
这是违反直觉的,但它有逻辑。以下是docs:
的控制流程图
[L]标志通常被宣传为停止递归的灵丹妙药,但实际上它只是确保一旦请求与模式匹配,那么执行就会停止,并且不会进行进一步的处理传递,但无论如何都会发出内部请求,因此第二次传递是通过相同的规则集进行的。只有在传递后URI未更改时,执行才会停止。
重新:更新 你的问题是,REQUEST_FILENAME环境变量实际上拥有一个路径(默认情况下是完整的文件系统路径,但是有一些扭曲),所以%{DOCUMENT_ROOT} / files /%{REQUEST_FILENAME}最终会变得非常糟糕。
至于解决方案......好吧,我觉得这很棘手。如果.htaccess是root用户,那就容易多了。我现在能想到的唯一解决方案是:
RewriteEngine on
RewriteCond %{REQUEST_URI} script/(.*)$
RewriteCond %{DOCUMENT_ROOT}/files/%1 -f
RewriteRule .* true.txt [L]
RewriteCond %{REQUEST_URI} !(true.txt)|(false.txt)
RewriteRule .* false.txt [L]
它相当丑陋,而且不具备扩展性或便携性。在第一个条件下,我得到文件的名称,在第二个我检查它是否存在,如果它存在,它是真的。其他一切都是假的。然后,如果文件目录也在.htaccess的范围内,那么它的大小就会更容易和更好。
答案 1 :(得分:1)
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} -f
RewriteCond %{REQUEST_URI} !(true|false)\.txt$
RewriteRule .* true.txt [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule .* false.txt [L]
注意第二个RewriteCond
以防止重写true.txt和false.txt文件,并在规则上L
标记以停止规则执行
这些是为了防止规则循环
<强>更新强>:
%{REQUEST_FILENAME}
是完整路径,因此如果您将其添加到某个路径,您将获得错误(它会尝试匹配此内容,基本上:/var/www/subfolder/var/www/filename.txt
要匹配其他文件夹中的文件,您需要匹配vs URI部分...
以下是您可以这样做的方法:
RewriteEngine on
RewriteBase /
RewriteCond %{REQUEST_URI} ^/([^/]+)$
RewriteCond %{DOCUMENT_ROOT}/files/%1 -f
RewriteRule .* files/$0 [L]
%1
中(由第一个条件匹配)存在于files/
%{DOCUMENT_ROOT}
中
答案 2 :(得分:0)
您可以尝试使用“RewriteCond%{REQUEST_FILENAME}!-f”代替: “RewriteCond%{THE_REQUEST}!-U”,用于检查地址是否存在 有时文件路径和提供文件的地址不同,使前者无法使用。
示例:
RewriteEngine On
RewriteCond %{THE_REQUEST} !-U
RewriteRule ^(.*/media/.*)\.(gif|png|jpe?g)$ https://xyz.company.com$1.$2 [NC,L,R=301]