多个 .htaccess 文件中多个 mod_rewrite 规则的优先级是啥? [关闭]

Posted

技术标签:

【中文标题】多个 .htaccess 文件中多个 mod_rewrite 规则的优先级是啥? [关闭]【英文标题】:What is the precedence of multiple mod_rewrite rules in multiple .htaccess files? [closed]多个 .htaccess 文件中多个 mod_rewrite 规则的优先级是什么? [关闭] 【发布时间】:2013-03-29 22:59:10 【问题描述】:

我了解[L] 遵循重写规则意味着它是“最后一个”,但我不清楚范围是什么

例如,当有多个.htaccess文件时,有的带有[L],哪些会适用?

例子:

root.com/subdirectory1/subdirectory2

  ^           ^            ^      
  |           |            |
  A           B            C

如果每个目录下都有.htaccess文件...

    它们将按什么顺序应用? 如果它们相互矛盾,哪个优先? 它们是否连续应用?第一次的结果会传递给下一次吗? 是否会应用较早(或相同)文件中的匹配结果,该文件来自较晚的规则? 如果早期文件中有[L],是否会考虑其他文件?

【问题讨论】:

@casperOne:这是一个编程问题,恕我直言。 htacess 文件,更具体地说是 OP 询问的重写规则,会影响 Web 应用程序中的控制流。 “执行优先级”听起来确实像是程序员的问题,不是吗? 【参考方案1】:

[L] 标志确实意味着“最后一个”,但它只适用于当前范围内的规则。根据您的问题,它仅适用于 htaccess 文件中的规则。如果子目录中有规则,则父目录中的任何规则都将被抛出窗口。它们根本不应用,除非您使用 RewriteOptions Inherit 指令(它会将父 htaccess 文件中的任何规则附加到规则的末尾)。

举个例子:

root.com/subdirectory1/subdirectory2
  ^           ^            ^      
  |           |            |
  A           B            C

如果A、B、C中都有htaccess文件,并且全部3个都重写规则,如果有一个请求http://root.com(你的“root.com”目录),只有A中的规则被应用。如果有人请求http://root.com/subdirectory1,则只应用 B 中的规则,而忽略 A 中的任何规则(没有 Inherit 选项)。同样,如果有人转到http://root.com/subdirectory1/subdirectory2,那么如果没有继承选项,则只会应用 C 中的规则。

[L] 标志在其中没有任何作用,因为这里的范围仅在 htaccess 文件的规则内。另请注意,[L] 并不一定意味着“停止重写 HERE”,因为重写引擎将循环直到进入引擎的 URI 停止更改。 [L] 只是意味着在重写引擎循环的当前迭代中停止重写。


关于循环的更多细节:

在 URL 处理管道期间,apache 尝试将 URL 映射到文件或资源。许多不同的模块在处理管道中发挥作用,例如 mod_rewrite 或 mod_proxy 或 mod_alias。在任何时候,此 URI 都可以更改、被标记为重定向、被标记为被代理、被标记为抛出错误等。当 URI 到达 mod_rewrite 时,重写引擎从 vhost 配置中收集一堆规则并适当的 htaccess 文件;请注意,这里有 2 个不同的范围。每个规则范围都应用于 URI,如果没有规则匹配,则 mod_rewrite 完成。如果其中一个规则匹配,则存在 内部重定向,这意味着 URI 已更改,然后重定向回处理管道和 mod_rewrite。因此,相同范围的规则再次被应用,如果其中一个规则匹配并被应用,同样的事情再次发生在规则循环中。您可以在名为LimitInternalRecursion 的虚拟主机/服务器配置中设置一个指令,该指令设置这些内部重定向的限制。如果重写引擎循环(即重定向回自身)的次数超过此限制(我认为默认为 10),那么您会收到 500 Internal Server 错误。

这可能听起来有点奇怪,但有很多例子想要这样做。示例:从 URI 中删除所有 _ 并替换为 -

RewriteRule ^(.*)_(.*)$ /$1-$2 [L]

如果 URI 是 /a_b_c_d_foo,那么第一次,URI 将更改为 /a_b_c_d-foo,然后循环并更改为 `/a_b_c-d-foo,然后再次更改为 /a_b-c-d-foo,到第五次您将获得 @987654339 @。它将再次循环,但由于^(.*)_(.*)$ 模式不匹配,URI 通过重写引擎并停止循环。

当人们创建不考虑循环的规则时就会出现问题,例如:将/<anything> 重写为/foo/<anything>

RewriteRule ^(.*)$ /foo/$1 [L]

如果 URI 是 /bar,那么 URI 第一次被重写为 /foo/bar,这就是想要的结果。但是 URI 在内部被重定向回重写引擎,并且再次匹配相同的规则,导致:/foo/foo/bar,然后是:/foo/foo/foo/bar,然后是:/foo/foo/foo/foo/bar,直到达到内部递归限制并得到500 服务器错误。

【讨论】:

+1 写得很好。 这很棒。您能否澄清答案中的最后一句话?我从您的回答中学到了很多东西,但我不明白重写引擎“循环”的方式。 @Emerson 查看附加说明 啊哈!在最后一个有问题的示例中, [L] 无济于事,因为它只会阻止该特定循环中的进一步重写,而不是未来循环的发生。我明白了吗? @JonLin 再问一个问题:在循环过程中,如果遇到外部重写,是否会立即中断循环?例如,如果A 中的.htaccess 有RewriteRule ^(.*)$ http://www.google.com [R=301,L] 之类的东西,那么所有较低的.htaccess 都会变得无关紧要吗?

以上是关于多个 .htaccess 文件中多个 mod_rewrite 规则的优先级是啥? [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

一个 .htaccess 文件中有多个 RewriteBase?

一个 .htaccess 文件中有多个 RewriteBase?

如果一个网站在文件树中多次存在,它可以使用多个 .htaccess 文件吗?

如何在 .htaccess 中输入多个 PHP 值?

拒绝访问 htaccess 中的多个文件

虚拟云主机创建多个站点方法(.htaccess实现)