Apache 不匹配重寫的 URL 作為正常文件
我已經設置了一個
.htaccess
將針對包含目錄的請求重定向/htdocs/foo
到文件bar.php
。首先:我知道一般如何實現這一點,但由於我無法控制的原因,我
.htaccess
還想檢查 URL 是否解析為正常文件,如果沒有則重定向。聽起來不太複雜,但我無法解決這個問題。:[
這是我的
.htaccess
:RewriteRule ^$ http://www.example.com/foo/bar.php RewriteCond %{REQUEST_FILENAME} !-f RewriteRule .* doh.php
這些規則不會重定向
www.example.com/foo
到bar.php
,而是doh.php
。我檢查了儘管文件存在,
error.log
但由於某種原因,重寫條件匹配。bar.php
RewriteCond: input='http://www.example.com/foo/bar.php' pattern='!-f' => matched
bar.php
顯然,如果重寫的 URL 指向它,Apache 不會將其視為正常文件。www.example.com/foo/bar.php
按預期工作。任何想法為什麼?
編輯#1:
為了澄清,這是文件結構:
/ (File system root) | + htdocs (Document root) | + foo | + .htaccess + bar.php + doh.php
編輯#2:
我正在執行 Apache 2.4。
解決方案:
RewriteCond
期望REQUEST_FILENAME
包含一個本地路徑。由於缺少L
標誌,RewriteRule
設置REQUEST_FILENAME
為顯然不是本地路徑的 URL,因此測試!-f
匹配。最終,將
L
標誌附加到RewriteRule
產生所需的行為:RewriteRule ^$ http://www.example.com/foo/bar.php [L] RewriteCond %{REQUEST_FILENAME} !-f RewriteRule .* doh.php
將 URL 重寫為
http://www.example.com/foo/bar.php
新的程序循環後,將重新映射重寫的 URL 到與測試/htdocs/foo/bar.php
不匹配的RewriteCond
本地路徑!-f
。並且/htdocs/foo/bar.php
是通過的。:)
RewriteCond: input='/htdocs/foo/bar.php' pattern='!-f' => matched
不確定這是否被過度舉例說明,但除非有“其他事情”發生,否則根據上述指令,這不是預期的。
由於您的初始(隱含)重定向缺少
L
標誌,因此處理立即繼續到下一個指令。此時,我希望在日誌中看到類似以下內容:RewriteCond: input='http://www.example.com/foo/bar.php' pattern='!-f' => matched
在第一個之後
RewriteRule
,該REQUEST_FILENAME
指令將按原樣更新為最後一個RewriteRule
ie 的輸出。http://www.example.com/foo/bar.php
. 在這個階段它不會重新映射到文件系統。(除非您指定了相對路徑替換,在這種情況下,目錄前綴將被添加 - 這似乎是您在日誌中看到的 - 但這與問題中的指令不對應。)因此,上述條件確實是“匹配的”——“絕對 URL”不可能作為文件系統中的文件存在。
然後你會得到一個損壞的302“重寫”到
doh.php
. 請求在內部被重寫為doh.php
,但是HTTP狀態從之前的“重定向”設置為302,但是沒有Location
標頭,所以沒有外部重定向。(雖然你似乎暗示有一個“重定向”到doh.php
?)RewriteRule ^$ http://www.example.com/foo/bar.php
為了觸發外部重定向(考慮到後面的重寫),您需要包含
L
(last
) 標誌以停止目前輪的處理。您還應該明確並包含
R
標誌。此處隱含 302 重定向,因為您已在RewriteRule
.例如:
RewriteRule ^$ http://www.example.com/foo/bar.php [R,L]
在旁邊:
這些規則不會重定向
www.example.com/foo
請注意,如果您請求
/foo
沒有尾部斜杠並且/foo
是物理目錄,則 mod_dir 將首先隱式 301 重定向到/foo/
,以便通過附加尾部斜杠來“修復”URL。