【问题标题】:Why this modrewrite rule not having an redirect loop为什么这个 modrewrite 规则没有重定向循环
【发布时间】:2013-12-09 07:33:37
【问题描述】:

Apache 版本:Apache/2.2.22 (Ubuntu)

我在.htaccess 文件中定义了以下重写规则

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

它工作正常(意味着它正在到达 goto 文件夹的 index.php)。但我认为它应该生成一个重定向循环。

假设一个网址是http://example.com/goto/foo。所以在第一次迭代中它将有http://example.com/goto/index.php?q=foo。在第二次迭代中,它应该匹配 rewriterule goto/(.*) 并且应该有一个重定向循环。

我的问题是它如何避免重定向循环?

我的 .htacces 文件只包含以下内容。

RewriteEngine on
RewriteRule ^goto/(.*)$ goto/index.php?q=$1 [L,QSA]

在 goto 文件夹内只有 index.php。那里没有其他文件。

编辑

我还使用 wamp 2.2 对此进行了测试 Apache 2.2.2 版

以下是重写日志

[perdir D:/wamp/www/test/blog/] strip per-dir prefix: D:/wamp/www/test/blog/goto/ddfd -> goto/ddfd
[perdir D:/wamp/www/test/blog/] applying pattern '^goto/(.*)$' to uri 'goto/ddfd'
[perdir D:/wamp/www/test/blog/] rewrite 'goto/ddfd' -> 'goto/index.php?q=ddfd'
split uri=goto/index.php?q=ddfd -> uri=goto/index.php, args=q=ddfd
[perdir D:/wamp/www/test/blog/] add per-dir prefix: goto/index.php -> D:/wamp/www/test/blog/goto/index.php
[perdir D:/wamp/www/test/blog/] strip document_root prefix: D:/wamp/www/test/blog/goto/index.php -> /test/blog/goto/index.php
[perdir D:/wamp/www/test/blog/] internal redirect with /test/blog/goto/index.php [INTERNAL REDIRECT]
[perdir D:/wamp/www/test/blog/] strip per-dir prefix: D:/wamp/www/test/blog/goto/index.php -> goto/index.php
[perdir D:/wamp/www/test/blog/] applying pattern '^goto/(.*)$' to uri 'goto/index.php'
[perdir D:/wamp/www/test/blog/] rewrite 'goto/index.php' -> 'goto/index.php?q=index.php'
split uri=goto/index.php?q=index.php -> uri=goto/index.php, args=q=index.php&q=ddfd
[perdir D:/wamp/www/test/blog/] add per-dir prefix: goto/index.php -> D:/wamp/www/test/blog/goto/index.php
[perdir D:/wamp/www/test/blog/] initial URL equal rewritten URL: D:/wamp/www/test/blog/goto/index.php [IGNORING REWRITE]

最后一个条目说它正在忽略重写。那么在这种情况下,实际上是什么配置指示忽略重写?

【问题讨论】:

  • 来自文档,The [L] flag causes mod_rewrite to stop processing the rule set.doc
  • @HussainTamboli 但是.htaccess 中的[L] 标志只会停止当前循环。它将返回它当前重写的内容,一遍又一遍地调用.htaccess,直到url停止变化。
  • @chanchal118:我的猜测是你可能有goto/.htaccess 或者当前.htaccess 中的其他一些,它正在重写这个。
  • 如果您没有收到错误,请检查您的 httpd.conf 文件。
  • @Sumurai8 我的 apache 版本是 Apache/2.2.22 (Ubuntu) 。我应该在 apache2.conf 中寻找哪个配置/指令?

标签: apache .htaccess mod-rewrite


【解决方案1】:

在我的设置中,这条规则确实会导致无限循环。它最终会给出500 Internal Error,因为它超过了内部重定向的最大数量。在.htaccess 中,[L] 标志只会停止当前的重写周期以停止,但不会阻止新周期的发生。它只会在 url 停止更改时停止。 (这与httpd.conf 中的行为不同,当不在每个目录上下文中时,[L] 标志将完全停止重写)

有几种方法可以停止无限循环。

#1. Any url with index.php in it will not be rewritten
RewriteRule index\.php - [L]
RewriteRule ^goto/(.*)$ goto/index.php?q=$1 [L,QSA]

每个带有 index.php 的 url 都会匹配第一条规则。因为url没有重写,所以不会发起新的循环。

#2. Exclude 
RewriteCond %{REQUEST_URI} !^/goto/index\.php$
RewriteRule ^goto/(.*)$ goto/index.php?q=$1 [L,QSA]

使用条件检查 index.php 是否不在当前 url 中

#3. Use the END flag
RewriteRule ^goto/(.*)$ goto/index.php?q=$1 [END,QSA]

使用END 标志。请注意,此标志仅适用于 Apache 2.3.9 及更高版本。它将在.htaccess 上下文中完全停止重写。

【讨论】:

  • 但是,您没有解释为什么 OP 的设置中没有无限循环,或者是吗?
  • 如果有其他规则正在处理/goto/index.php 或Apache 的系统特定实现发现将/goto/index.php?q=asdf 重写为/goto/index.php?q=asdf 是“否”,则不会生成无限循环改变'。在我的更改中,只有对- 的重写将被视为。您必须查看您的 rewritelog 以确切了解正在发生的事情以及 mod_rewrite 做出的决定。我无法猜测某个操作系统/某个 Apache 版本上发生了什么。
【解决方案2】:

实际上这是由于该 URL 的目标 URL 中不存在前导斜杠:

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

现在在goto 之前用斜杠尝试这条规则:

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

现在您会注意到无限循环错误。

原因是在第一种情况下,目标 URI 不以斜杠开头。在这种情况下,mod_rewrite 足够聪明,可以防止无限循环,因为它检测到goto/index.php 的原始请求与第一次通过后对goto/index.php 的内部重写相同,因此它不会执行进一步的重写这条消息在RewriteLog:

[IGNORING REWRITE]

【讨论】:

    【解决方案3】:

    感谢您的更新。由于直到(但不包括)查询字符串的第一个重写的 URI 与直到同一点的第二个重写的 URI 相同,所以它被丢弃为冗余。这是 mod_rewrite 的一个功能,旨在防止无限重写循环。如果您将规则替换为:

    重写规则 ^goto/(.*)$ /goto/index.php?q=$1 [L,QSA]

    (注意替换前面的“/”),假设 goto 在 DocumentRoot 中,您将得到您期望的循环。这是因为“/goto/index.php”(结果)与“goto/index.php”(最初匹配的URI)不同。

    -- 原始答案如下--

    你能证实你实际上是在重写任何东西吗?我问是因为这是从相对路径到相对路径的重写,并且您在 .htaccess 文件中没有 RewriteBase 指令。除非 .htaccess 在服务器(或虚拟主机)的 DocumentRoot 目录中,否则重写引擎需要 RewriteBase 来确定如何完成重写。

    此外,即使它位于 DocumentRoot 目录中(这意味着要重写的原始 URL 是 http://example.com/goto/foo),除非有一个 AllowOverride 指令提供 FileInfo 覆盖权限,并且有一个 Options 指令指定 FollowSymLinks , 对目录有效,.htaccess 文件中的 mod_rewrite 指令被忽略。

    至于“到达 index.php”——在没有看到配置的情况下,我真的无法评论为什么它成功地提供了一个页面,尽管没有重写。可能是 ErrorDocument 指令为您提供了与您期望的页面相匹配的页面。服务器或虚拟主机配置文件中甚至可能有一些重写规则来处理 /([^/]+)/index.php 存在的情况,重写会生成 404 错误代码以使用适当索引的请求。 php 文件,而不是。

    参考资料:

    http://httpd.apache.org/docs/2.2/mod/mod_rewrite.html#rewriterule - 解释重写工作必须满足哪些条件。

    http://httpd.apache.org/docs/2.2/mod/core.html#allowoverride - 记录 AllowOverride 指令的 FileInfo 关键字。

    http://codex.wordpress.org/htaccess - 描述了几种管理重写 index.php 的方法

    【讨论】:

    • 感谢您的更新。由于直到(但不包括)查询字符串的第一个重写的 URI 与直到同一点的第二个重写的 URI 相同,所以它被丢弃为冗余。这是 mod_rewrite 的一个功能,旨在防止无限重写循环。如果你用 'RewriteRule ^goto/(.*)$ /goto/index.php?q=$1 [L,QSA]' 替换你的规则,而不是(注意替换前面的'/'),假设 goto 是在 DocumentRoot 中,你会得到你期望的循环。
    • 你能修改你在最后评论中写的答案吗?实际上就是这种情况。
    猜你喜欢
    • 1970-01-01
    • 2010-12-09
    • 1970-01-01
    • 2011-11-22
    • 2012-02-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多