Apache以404而不是403响应,忽略F标志

Apache以404而不是403响应,忽略F标志,apache,.htaccess,mod-rewrite,Apache,.htaccess,Mod Rewrite,我有一个简单的项目层次结构: 位于/www根文件夹的.htaccess文件的内容包括: RewriteEngine On RewriteRule ^index\.php$ - [L] RewriteCond %{REQUEST_FILENAME} "\.php$" RewriteRule .* - [F] 当请求任何.php文件但index.php时,.htaccess中的规则应返回403。php模板的内容不相关 如果我没有错,如果请求的最后一部分是现有.php文件的

我有一个简单的项目层次结构:

位于
/www
根文件夹的
.htaccess
文件的内容包括:

RewriteEngine On

RewriteRule ^index\.php$ - [L]

RewriteCond %{REQUEST_FILENAME} "\.php$"
RewriteRule .* - [F]
当请求任何.php文件但
index.php
时,
.htaccess
中的规则应返回403。php模板的内容不相关

如果我没有错,如果请求的最后一部分是现有.php文件的名称,并且重写引擎处于启用状态,则无论您是否指定.php部分,Apache都会为其提供服务。在我的例子中,如果我注释掉
.htaccess
的最后两行,则以下任何URL:

localhost/pages/page 
localhost/pages/page/
返回
/pages/page.php的内容

我的问题是,鉴于上述
.htaccess
,如果我编写此url:

localhost/pages/page.php
我得到了预期的403。但如果我写下以下任何一项:

localhost/pages/page
localhost/pages/page/

我得到了一个404(未找到),而不是预期的403。为什么我会得到404呢?

很有趣。。。我可以在Apache2.4上重现这种行为,但无法解释它-在我看来这像是一个bug,因为用
R=403
替换
F
会产生所需的结果(应该没有区别)-见下文

为了澄清,要将
/pages/page
解析为
/pages/page.php
首先取决于启用的
多视图
(如注释中所述)。或者,您可以使用mod_rewrite来实现这一点,但这里没有证据证明这一点。Apache上默认情况下禁用多视图,但某些共享主机出于某种原因启用了多视图(这使无扩展URL“正常工作”)。但是,多视图是与mod_rewrite发生意外冲突的常见原因。无扩展URL“只是(意外地)工作”这一事实可能会导致规范化方面的其他问题

我认为存在“bug”的原因是,如果您简单地将
F
标志更改为
R=403
,那么您确实会得到“预期的”403响应:

F
R=403
之间应该没有区别。好吧,
F
只是一条捷径


我尝试了
选项-多视图
,但得到了相同的结果

但是,禁用多视图时,404是预期的响应


禁用多视图后,如果您请求
/pages/page
请求文件名
的格式将为
/abs/path/to/pages/page
(无
.php
扩展名)。您的条件不匹配,因此请求通过404

您最好使用禁用的多视图。对于
/pages/page
/pages/page/
来说,“神奇地”解析为
/pages/page.php
,这是不“正常的”。在这种情况下,
/pages/page
/pages/page/
导致404是“正常”的。如果您使用mod_rewrite做了很多工作,请求的URL映射到文件系统,那么您可能会遇到冲突

请注意,多视图不仅仅适用于
.php
文件。启用多视图后,您将拥有无扩展的一切。图像、脚本、HTML、样式表等。如果您有多个具有公共基名称和mime类型的文件,将提供哪些服务?例如
foo.php
foo.html

当然,您可以创建mod_rewrite指令来启用此行为,但这不是自动的


更新:一个更简洁的示例

给定一个文件
/page.php
(在文档根目录中)并启用多视图。
(例如,
选项+多视图

请求
/page
(或
/page/
)会导致多视图/mod_协商服务
/page.php
而不是内部子请求

现在,让我们用mod_rewrite阻止所有访问,并提供403禁止:

RewriteRule ^ - [F]
这将用403阻止每个请求。但是,请求
/page
/page/
(一个由多视图成功重写的URL)会导致404 Not Found响应

但是,将上述规则更改为使用
R
标志:

RewriteRule ^ - [R=403]

现在,所有内容都返回403,包括上面提到的两个URL!但是
F
R=403
应该会导致相同的行为。

“如果请求的最后一部分是现有.php文件的名称,并且重写引擎处于启用状态,则无论您是否指定.php部分,Apache都会为其提供服务。”-这不是mod_rewrite的做法,这是多视图的效果。我的猜测是,它可能在这里也会干扰,所以请尝试使用
选项-MultiViews
@CBroe禁用它。我曾尝试使用
选项-MultiViews
,但如果不启用MultiViews,我会得到相同的结果,我不明白
/www/pages/page
/www/pages/page/
如何让它首先找到
/www/pages/page.php
请求文件名
此时还不一定解析为实际的物理文件名,因此它可能仍然包含与
请求URI
相同的内容。因此,对于
/www/pages/page/
,通过在现有文件末尾附加
.php
来测试该文件将不起作用。@CBrow我认为启用该行为的模块(我猜是内容协商模块?)在本地主机Apache安装中默认启用。无论如何,我已经尝试将301重定向到index.php,并将
REQUEST\u FILENAME
附加为querystring参数:
RewriteRule。index.php?q=%{REQUEST_FILENAME}[R=301,L]
并以实际文件路径响应:
https://localhost/index.php?q=D:/wamp64/www/pages/page.php
当我输入url时
https://localhost/pages/page
那么,是否应该以某种方式报告此问题?您正在运行什么版本的Apache,在什么平台上运行?诚然,我正在Apache2.4.7的一个相当旧的版本(在W
RewriteRule ^ - [R=403]