5 七月, 2005

Apache mod_rewrite的死循环问题

通过mod_rewrite来重定向url,如果规则写的不正确,很容易造成死循环,特别是对per-dir(目录级)的规则(.htaccess)更是如此。Apache 1.3.28以后的版本增加了RewriteOptions MaxRedirects选项,限制了redirect的次数。这以前的版本,会因为规则设置不当而无限地循环下去,相应的httpd进程占用大量CPU资源,甚至令服务器资源耗尽,无法正常工作。

举个例子:

在某个目录下(e.g. /test/)的.htaccess文件中

规则A把.asp改写成.jsp
又有一个规则B把.jsp改写成.asp

这就必然导致循环匹配

RewriteRule中的“last|L”flag虽然可以阻止成功匹配后进一步的规则匹配尝试,但是由于mod_rewrite实现per-dir重定向方式的特殊技巧,使得死循环仍然成为可能,而并不是象hedong所说的“这两个规则是有先后的,且只执行一次”。

让我们先来看看mod_rewrite的这个特殊技巧。http://httpd.apache.org/docs/mod/mod_rewrite.html#InternalAPI这 一节中是这么说的:等到apache API已经可以取得某个目录下的.htaccess的时候,URL已经被映射成file-name了,这时候再做URL重定向已经太晚了。为了克服这个问 题,mod_rewrite使用了一点点小技巧,它根据RewriteBase的设置,将file-name重新还原成为URL,并调用internal redirect过程,重头开始。这就给mod_rewrite一个机会,可以apply写在.htaccess内的目录级匹配规则。需要注意的是,这里 的internal redirect是由mod_rewrite发起的子级请求,所以它不会被“nosubreq|NS”过滤。

现在再来看看我们的例子。假设有这样一个请求:http://www.utblog.com/test/cb.asp。那么根据规则A,它将被重定向到http://www.utblog.com/test/cb.jsp,正因为有“L”, 所以不会在这一次的Fixup阶段陷入死循环。Apache继续处理这个internal redirect请求,因为这等同于一个新请求,所以mod_rewrite还是会在新的Fixup阶段再次尝试匹配,这次,它应用规则B,结果,这个 /test/cb.jsp的请求又被重定向成为/test/cb.asp...如此反复,直到重定向次数达到MaxRedirects的限制为止。

btw,对于整个server级(per-server)的Rewrite规则(在httpd.conf中定义),一般来说,只要加上“last|L”选项,就不会有死循环的问题。又因为不需要internal redirect步骤,server级URL重定向的效率也比per-dir的高很多。

referrence:

http://httpd.apache.org/docs/mod/mod_rewrite.html

http://httpd.apache.org/docs/misc/rewriteguide.html

Apache的Mod_rewrite学习(一)


最新回复

MaxRedirects is an important option. upgrade apache server to 1.3.26 at least

作者 风 10 七月 2005, 13:00
发表评论


















Bold Italic Link