我有一个 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
这招很管用。