Apache .htaccess RewriteRule 和 ErrorDocument

Apache .htaccess RewriteRule 和 ErrorDocument

我有一个.htaccess文件:

RewriteEngine On
DirectorySlash Off

RewriteCond %{REQUEST_URI}  !(\.css|\.js|\.png|\.jpg|\.mp4|\.ttf|\.eot|\.woff)$
RewriteRule ^(.*)$ ?page=$1 [NC,L,QSA]

ErrorDocument 404 /e404
ErrorDocument 403 /e404
ErrorDocument 500 /e500

还有一个 PHP 函数用于检查所请求的 URI 是否存在。如果数据库中存在该 URI,它将获取内容并呈现页面;如果不存在,它将获取 404 错误页面内容并呈现页面。(这里一切正常)

问题是当我使用带有RewriteCond文件部分内部扩展名的 URI 时.htaccess,例如example.com/file.css。在这种情况下,页面被重定向到example.com/e404 (这就是我想要的)。这里的问题是:

我不知道如何获取重定向到之前使用的“错误 URI” example.com/e404,因为在加载错误页面时,我在页面内部有一个函数可以将“错误的 URI”插入数据库中。

答案1

在旁边:您发布的指令会在任何默认的 Apache 安装上创建重写循环,所以也许您还有其他指令或不同的配置,而您没有在问题中披露这些配置?无论如何,暂时忽略这个问题,因为您似乎没有遇到这样的问题。

我不知道如何在重定向到之前获取使用的错误 URI example.com/e404...

但你需要得到这些信息吗“重定向”?在 PHP 中,您只需检查$_SERVER['REQUEST_URI']超全局变量即可获取此信息(导致 404 的 URL)。但是,请注意,这包含斜杠前缀和查询字符串(如果有),否则您的pageURL 参数不会包含这些内容。

另外,为了澄清术语,严格来说,这并不是“重定向”到example.com/e404。“重定向”意味着外部 HTTP 重定向。Apache 发出内部子请求用于错误文档(类似于URL重写,但不完全一样)。

您的代码可能存在的一个问题是 404 响应是以一种相当迂回的方式提供的:

  1. 如果file.css不存在,那么 Apache 将触发内部子请求/e404
    (这会触发另一轮处理......)
  2. 由于/e404没有以所述文件扩展名之一结尾,因此它被进一步重写为?page=e404(大概是index.php?)。

由于(不必要的)第二次重写,其他服务器变量(例如REDIRECT_URLREDIRECT_QUERY_STRING(也传递到 PHP$_SERVER超全局变量))未按预期设置。通常,这些变量将被设置为“错误的 URI”(即触发 404 的请求 URL),但它们却包含错误文档本身的详细信息。

您应该一步完成上述操作,避免第二次重写。例如(假设index.php是处理请求的文件),错误文档应设置为所需的最终结果:

ErrorDocument 404 /index.php?page=e404

顺便说一句,您不一定需要e404在 URL 中明确传递 HTTP“错误状态”(即),因为这在 PHP 的$_SERVER['REDIRECT_STATUS']超全局变量中可用。

RewriteRule ^(.*)$ ?page=$1 [NC,L,QSA]

我假设您正在重写index.php(已注册的 DirectoryIndex)?您不应该让 mod_dir 为 DirectoryIndex 发出额外的子请求,而应该明确说明并将您要重写的文件包含在代换。 例如:

RewriteRule ^(.*)$ index.php?page=$1 [QSA,L]

NC这里的旗帜是多余的。)

我不知道如何在重定向到之前获取使用的错误 URI example.com/e404...

退一步来再次回答你最初的疑问(作为学术练习)。你可以在 Apache 2.4.13+ 上执行此操作(尽管我不认为你需要至)。在 Apache 2.4.13+ 上,您可以使用 Apache 表达式创建动态 ErrorDocument。

例如,为了在错误文档本身的 URL 中明确传递导致 404 错误的 URL 路径,您可以执行以下操作:

ErrorDocument 404 /index.php?page=%{escape:%{REQUEST_URI}}&error=404

然后URL 参数page包含 URL 路径(其中包括斜杠前缀,而重写则不包括它)。附加errorURL 参数发送 HTTP 状态(尽管如上所述,这不是绝对必要的)。

相关内容