多个.htaccess文件中多个mod_rewrite规则的优先级是什么?

时间:2013-04-08 00:01:10

标签: apache .htaccess mod-rewrite url-rewriting

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

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

示例:

root.com/subdirectory1/subdirectory2

  ^           ^            ^      
  |           |            |
  A           B            C

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

  1. 他们会以什么顺序申请?
  2. 如果他们互相矛盾哪个优先?
  3. 他们是否连续申请?第一个结果是否传递到下一个?
  4. 是否会在较早(或相同)的文件中匹配来自后来规则的RESULT?
  5. 如果早期文件中有[L],是否会考虑其他文件?

1 个答案:

答案 0 :(得分:14)

[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的vhost / server配置中设置指令,该配置设置这些内部重定向的限制。如果重写引擎循环(即重定向回自身)的次数超过此限制(我认为默认值为10),则会出现500内部服务器错误。

这可能听起来很奇怪但是有很多例子想要这样做。示例:从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并通过第5次你得到/a-b-c-d-foo。它会再次循环但由于^(.*)_(.*)$模式不匹配,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服务器错误。