如何向 RewriteRule 添加条件以排除子目录中不存在的文件?

How can I add a condition to RewriteRule that would exclude files that do not exist in a subdirectory?

如果页面不存在,我希望排除规则被调用。在我现有的 htaccess 中,当用户访问根目录中不存在的页面时,此规则将按预期工作。奇怪的是,如果用户试图访问不存在的有效页面的子目录,它就不起作用。

我的 htaccess 的当前行为:

example.com/valid-page/ -> example.com/valid-page/ (good)
example.com/valid-page -> example.com/valid-page/ (good)
example.com/valid-page/valid-page -> example.com/valid-page/valid-page/ (good)
example.com/does-not-exist -> example.com/does-not-exist (good)
example.com/valid-page/does-not-exist -> example.com/valid-page/does-not-exist/ (boo!)

对于上面的错误示例,期望的结果应该是不包含正斜杠:

example.com/valid-page/does-not-exist -> example.com/valid-page/does-not-exist

这是 .htaccess:

# Redirects for errors
ErrorDocument 404 /error.php
ErrorDocument 403 /error.php

# Hides directory file listings
Options -Indexes

# Turn mod_rewrite on
RewriteEngine On
RewriteBase /

# Force slash at end of URL
RewriteCond %{REQUEST_URI} /+[^\.]+$
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^(.+[^/])$ %{REQUEST_URI}/ [R=301,L]

# To externally redirect /dir/foo.php to /dir/foo
RewriteCond %{THE_REQUEST} ^[A-Z]{3,}\s([^.]+)\.php [NC]
RewriteRule ^ %1 [R,L]

# To internally forward /dir/foo to /dir/foo.php
RewriteCond %{SCRIPT_FILENAME} !-d
RewriteRule ^([^.]+)/$ .php [NC,L]
# Force slash at end of URL
RewriteCond %{REQUEST_URI} /+[^\.]+$
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^(.+[^/])$ %{REQUEST_URI}/ [R=301,L]

您需要更改检查 REQUEST_FILENAME 的第二个 条件 ,因为当您请求 /valid-page/does-not-exist 时,REQUEST_FILENAME.../valid-page,而不是您期望的 .../valid-page/does-not-exist

而不是 REQUEST_FILENAME,使用 REQUEST_URI(或 </code> 反向引用)并构造绝对文件名。例如:</p> <pre><code># Force slash at end of URL RewriteCond %{REQUEST_URI} /+[^\.]+$ RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI}.php -f RewriteRule ^(.+[^/])$ %{REQUEST_URI}/ [R=301,L]

您需要在测试前清除浏览器缓存,因为浏览器会缓存错误的 301(永久)重定向。使用 302(临时)重定向进行测试以避免缓存问题。

现在,当您请求 /valid-page/does-not-exist 时,您正在检查 .../valid-page/does-not-exist.php 是否作为文件存在,而不是像以前那样 .../valid-page.php

my answer to the following question on ServerFault which goes into more detail about what REQUEST_FILENAME is actually set to. https://serverfault.com/questions/989333/using-apache-rewrite-rules-in-htaccess-to-remove-html-causing-a-500-error