在我的 Apache 设置中,我有一个包含错误页面的目录(404 403)。但是,我不希望直接查看此目录 - 我希望访问它以返回 404。所以我做了以下事情:
# Use /hidden/404/ as the 404 page
ErrorDocument 404 /hidden/404/
# Use /hidden/403/ as the 403 page
ErrorDocument 403 /hidden/403/
<Directory /path/to/root/hidden/>
# All requests return 404
RedirectMatch 404 .*
</Directory>
问题是 Apache 似乎不愿意提供以下文件:全部在这种情况下,即使我明确告诉它(即处理 404 和 403 错误),它也会出错。事实上,当我访问 时/hidden
,我收到以下消息:
The requested URL /hidden/404/ was not found on this server.
Additionally, a 404 Not Found error was encountered while trying to use an
ErrorDocument to handle the request.
有什么方法可以告诉 Apache 不允许访问该目录,但在必要时仍允许其提供这些文件?
答案1
好的,我找到一种方法来做到这一点。
我所做的是使用mod_rewrite
,这是一个 Apache 模块(默认情况下随所有安装一起提供),用于动态重写请求的 URL。以下是代码:
# Custom error pages
ErrorDocument 404 /hidden/404/index.html
ErrorDocument 403 /hidden/403/index.html
# Pretend that /hidden doesn't exist
# (unless this is an internal redirect,
# such as rendering a 404 or 403)
RewriteCond %{ENV:REDIRECT_STATUS} =""
RewriteRule ^/hidden/.* - [L,R=404]
让我们来看看这些代码。ErrorDocument
指令没有改变 - 它们只是说明当发生给定错误时应该提供哪个页面。
真正的重点在于RewriteCond
andRewriteRule
指令。RewriteRule
指令的内容如下:如果请求的 URL 路径与正则表达式匹配^/hidden/.*
(本质上,任何路径都指向 /hidden/ 或其子树中的任何内容),则保留 URL 不变(这就是 的意思-
),但不再解释任何RewriteRule
指令(这就是 的意思L
),并返回 404 错误代码(这就是 的意思R=404
)。
这与ErrorDocument 404 /hidden/404/index.html
指令相结合,似乎可以解决问题。但问题是,当 Apache 开始服务时/hidden/404/index.html
,它会再次运行这些规则。这意味着RewriteRule
指令被执行,指令又要求呈现 404,整个过程只是无限循环。
因此,我们使用RewriteCond
指令来确保这种情况不会发生。RewriteCond
指令是条件性的 -RewriteRule
下面的指令只有在条件满足时才会执行。在这种情况下,条件是“环境变量REDIRECT_STATUS
等于空字符串”。现在,REDIRECT_STATUS
是一个由设置的环境变量ErrorDocument
,并保存正在重定向的状态代码(因此,如果ErrorDocument 404 ...
触发了指令,它将被设置为值“404”)。但是,如果没有ErrorDocument
执行任何指令,则REDIRECT_STATUS
不会设置,因此请求其值只会返回空字符串。因此,本质上说,“除非我们没有在提供错误页面,否则RewriteCond %{ENV:REDIRECT_STATUS} =""
不要费心评估下面的指令。”RewriteRule
笔记:如果您查看了RewriteRule
文档,您可能已经注意到该R
参数应该执行显式重定向。它在本例中工作正常的原因是该R
参数有一个未记录的功能,即它仅在 300 类代码上重定向。因此,R=404
不执行显式重定向,只执行内部重定向。