为什么 apache 对存在的文件返回 404 响应?

为什么 apache 对存在的文件返回 404 响应?

我有一个 Apache 服务器,其主要目的是处理 RPC 请求。所有此类请求都会命中以固定前缀开头的 URL(例如/rpc),我使用Location指令来设置此 URL 的处理程序(例如<Location /rpc>...</Location>)。

我现在想让这台服务器也能提供静态文件。我把一个index.html文件放入其中DocumentRoot,但无法让 Apache 为我提供该文件。相反,我得到了 404 响应。访问日志显示以下内容:

127.0.0.1 - - [18/Aug/2010:11:41:52 -0400] "GET /index.html HTTP/1.1" 404 208

错误日志显示:

[...] [error] [client 127.0.0.1] File does not exist: /www/htdocs/index.html

这个错误信息简直就是个弥天大谎。我可以复制粘贴该路径,然后运行ls /www/htdocs/index.html,结果发现该文件确实存在。

到目前为止我尝试过的事情:

  • 检查了文件完整路径的所有权限:所有目录均为 755,所有文件均为 644
  • 检查所有权:所有目录和文件均由运行 apache 的同一用户拥有
  • 设置LogLevel debug(日志中没有出现新消息)
  • 添加<Location />带有SetHandler default-handler指令的块
  • 添加<Location /index.html>带有SetHandler default-handler指令的块
  • 将这两个块移到块的Location上方和下方<Location /rpc>
  • 运行dtruss后没有看到 apachestat()在处理请求时发出任何调用

我没什么主意了。我还应该尝试什么?

(我在 Mac OS X 10.5.8 上使用 apache 2.2.12,在 CentOS 5.4 上使用 apache 2.2.3。)

答案1

答案原来取决于我的问题中不存在的一条信息——但输出dtruss应该是一个很大的提示!

PerlMapToStorageHandler Apache2::Const::OK我的 apache 配置中有一个指令mod_perl 文档中的建议。这是一个主机范围的设置,它可以防止 apache 每次收到请求时调用ap_directory_walk()stat()加载一堆文件。当您的所有 URI 都是“虚拟”的(即不对应于磁盘上的实际文件)时,这是可取的,但这也意味着您无法提供任何静态文件!

我的解决方案是创建一个自定义PerlMapToStorageHandler例程,以避免stat()对除了我想要提供的文件之外的每个文件进行调用:

package MyMapToStorageHandler;

use strict;  
use Apache2::RequestRec();
use Apache2::Const -compile => qw(DECLINED OK M_TRACE);

sub handler {
    my $r = shift;

    # Fall through to the default handling for TRACE requests and requests
    # for the index.html file.
    if ($r->method_number == Apache2::Const::M_TRACE || $r->uri eq '/index.html') {
        return Apache2::Const::DECLINED;
    }

    # Skip ap_directory_walk stat() calls by just returning OK
    return Apache2::Const::OK;
}

1;

然后,在我的httpd.conf文件中,我PerlMapToStorageHandler Apache2::Const::OK用以下命令替换了我现有的指令:

PerlLoadModule MyMapToStorageHandler
...
PerlMapToStorageHandler MyMapToStorageHandler

这招很管用。

相关内容