为什么这个modrewrite规则没有重定向循环

时间:2013-12-09 07:33:37

标签: apache .htaccess mod-rewrite

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]

最后一句话说它是IGNORING REWRITE。那么在这种情况下,什么配置实际上是指示忽略重写?

3 个答案:

答案 0 :(得分:1)

在我的设置中,此规则确实会导致无限循环。它最终将提供500 Internal Error,因为它超过了内部重定向的最大数量。在.htaccess中,[L]标志只会停止当前重写周期停止,但不会停止新周期的发生。它只会在网址停止更改时停止。 (当httpd.conf标志不会完全停止重写时,这与[L]中的行为不同{/ em>

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

#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不会被重写,所以不会启动新的循环。

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

使用条件检查index.php是否不在当前网址

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

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

答案 1 :(得分:1)

实际上,这是因为此网址的目标网址中不存在前导斜杠:

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]

答案 2 :(得分:0)

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

RewriteRule ^ 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的方法