我想使用 mod_rewrite (在 .htaccess 中)将“干净”的 URL 映射到子目录中相应的 php 文件,例如:
https://example.com/test/
-->
https://example.com/p/test.php
我的第一步是向所有缺少斜杠的 URL 添加尾部斜杠:
RewriteEngine on
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !(.*)/$
RewriteRule ^(.*[^/])$ $1/ [L,R=301]
然后我添加了以下几行以确保路径/文件不存在:
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
最后是
RewriteRule
,将请求的路径映射到子目录中对应的文件/p/
:
RewriteRule ^(.+)$ /p/$1\.php
这似乎工作正常,除非我请求的 URL 不存在。那么操作就会导致死循环如:
https://example.com/p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/test/.php/.php/.php/.php/.php/.php/.php/.php/.php/.php/.php/.php/.php/.php/.php/.php/.php/.php/.php/.php/.php/.php/.php/.php/.php/.php/.php/.php/.php/.php/.php/.php/.php/.php/.php/.php/.php/
我已经尝试在
RewriteCond
之前添加另一个 RewriteRule
,以确保请求的文件确实存在于子文件夹 /p/
中,但我的方法不起作用:
RewriteCond %{DOCUMENT_ROOT}/p/$1.php -f
谁能告诉我我做错了什么?
我已经尝试在
之前添加另一个RewriteCond
,以确保请求的文件确实存在于子文件夹RewriteRule
中,但我的方法不起作用:/p/
是的,您需要这样做...检查您打算重写的文件是否确实存在,而不是重写任何不存在的文件。但是,您的“问题”是您的网址以尾部斜杠结尾,并且您似乎没有在规则中考虑到这一点。因此,如果请求
/test/
,您实际上是在尝试测试 %{DOCUMENT_ROOT}/p/test/.php
,而它自然不存在。
您需要排除
RewriteRule
pattern 中捕获子模式中的尾部斜杠。例如:
# Rewrite "/test/" to "/p/test.php" if it exists
RewriteCond %{DOCUMENT_ROOT}/p/$1.php -f
RewriteRule ^(.+)/$ p/$1.php [L]
不需要额外的文件系统检查(和开销)来检查请求是否映射到文件或目录 - 因为这些应该是互斥的事件。 (如果您确实有一个同名目录,则相应的
.php
文件将无法访问。)
您的完整文件将变为:
RewriteEngine on
# Append trailing slash (if omitted)
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.+[^/])$ /$1/ [R=301,L]
# Rewrite "/test/" to "/p/test.php" if it exists
RewriteCond %{DOCUMENT_ROOT}/p/$1.php -f
RewriteRule ^(.+)/$ p/$1.php [L]
请注意,规则中不需要附加尾部斜杠的第二个条件来测试请求的 URL 是否不以尾部斜杠结尾,因为这已经由
RewriteRule
pattern 处理(该模式只是如果尾部有斜杠,则不匹配)。