为什么这导致无限循环的要求? [英] Why does this cause an infinite request loop?

查看:173
本文介绍了为什么这导致无限循环的要求?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

今天早些时候,我在帮助别人与的.htaccess 使用的情况下,和<一href="http://stackoverflow.com/questions/5573485/php-htaccess-$p$ptty-url-in-reverse/5573650#5573650">came一个解决方案的作品,但不能完全弄明白自己!

Earlier today, I was helping someone with an .htaccess use case, and came up with a solution that works but can't quite figure it out myself!

他希望能够到:

  • 浏览的index.php ID = 3及?猫= 5
  • 查看地址栏读指数/ 3/5 /
  • 有内容服务从的index.php ID = 3及?猫= 5
  • Browse to index.php?id=3&cat=5
  • See the location bar read index/3/5/
  • Have the content served from index.php?id=3&cat=5

最后两个步骤是相当典型的(通常是进入索引的用户/ 3/5 摆在首位),但所需的第一个步骤,因为他仍然有在他的网站的一些旧格式的链接和,无论出于何种原因,也改变不了他们。所以他需要支持的两个的URL格式,并让用户始终最终看到了prettified之一。

The last two steps are fairly typical (usually from the user entering index/3/5 in the first place), but the first step was required because he still had some old-format links in his site and, for whatever reason, couldn't change them. So he needed to support both URL formats, and have the user always end up seeing the prettified one.

在很多对ING来回-ING,我们提出了以下的.htaccess 文件:

After much to-ing and fro-ing, we came up with the following .htaccess file:

RewriteEngine on

# Prevents browser looping, which does seem
#   to occur in some specific scenarios. Can't
#   explain the mechanics of this problem in
#   detail, but there we go.
RewriteCond %{ENV:REDIRECT_STATUS} 200
RewriteRule .* - [L]

# Hard-rewrite ("[R]") to "friendly" URL.
# Needs RewriteCond to match original querystring.
# Uses "?" in target to remove original querystring,
#   and "%n" backrefs to move its components.
# Target must be a full path as it's a hard-rewrite.
RewriteCond %{QUERY_STRING} ^id=(\d+)&cat=(\d+)$
RewriteRule ^index\.php$ http://example.com/index/%1/%2/? [L,R]

# Soft-rewrite from "friendly" URL to "real" URL.
# Transparent to browser.
RewriteRule ^index/(\d+)/(\d+)/$ /index.php?id=$1&cat=$2

虽然它似乎是一个有些奇怪的用例(为什么不直接使用摆在首位正确的链接?的,你可能会问),只是去用它。不管原来的要求,这是该方案,它的驾驶我疯了。

Whilst it might seem to be a somewhat strange use case ("why not just use the proper links in the first place?", you might ask), just go with it. Regardless of the original requirement, this is the scenario and it's driving me mad.

如果没有第一个规则,客户端进入的请求循环,试图 GET /索引/ X / Y / 反复并获得 302 各一次。在 REDIRECT_STATUS 的检查使一切顺利运行。不过,我本来以为最终规则后,没有更多的规则将被服务,客户不会作出任何更多的请求(注意,没有 [R] ),并一切都将是肉汁。

Without the first rule, the client enters into a request loop, trying to GET /index/X/Y/ repeatedly and getting 302 each time. The check on REDIRECT_STATUS makes everything run smoothly. But I would have thought that after the final rule, no more rules would be served, the client wouldn't make any more requests (note, no [R]), and everything would be gravy.

那么......为什么会有这样的结果在一个请求循环时,我拿出了第一条规则?

So... why would this result in a request loop when I take out the first rule?

推荐答案

而不能鼓捣你的设置,我可以肯定地说,但我相信这个问题是由于mod_rewrite的以下比较神秘的功能:

Without being able to tinker with your setup, I can't say for sure, but I believe this problem is due to the following relatively arcane feature of mod_rewrite:

当你在每个目录范围内的mod_rewrite处理的URL /文件名第一个重写的文件名回到其相应的URL(通常是不可能的,但看到下面的RewriteBase指令的伎俩来实现这一点),然后启动一个新的内部子请求新的URL。这将重新启动的API程序段处理。

When you manipulate a URL/filename in per-directory context mod_rewrite first rewrites the filename back to its corresponding URL (which is usually impossible, but see the RewriteBase directive below for the trick to achieve this) and then initiates a new internal sub-request with the new URL. This restarts processing of the API phases.

(来源: mod_rewrite的技术文档,我的的建议阅读本)

(source: mod_rewrite technical documentation, I highly recommend reading this)

在换句话说,当你使用重写规则的.htaccess 文件,它可能是新的,重写URL映射到文件系统上的一个完全不同的目录,在这种情况下,在原目录中的的.htaccess 文件将不再适用。因此,只要重写规则的.htaccess 文件匹配的要求,Apache在重新启动从头开始处理的 的修改后的URL。这意味着,除其他事项外,每重写规则再次被选中。

In other words, when you use a RewriteRule in an .htaccess file, it's possible that the new, rewritten URL maps to an entirely different directory on the filesystem, in which case the .htaccess file in the original directory wouldn't apply anymore. So whenever a RewriteRule in an .htaccess file matches the request, Apache has to restart processing from scratch with the modified URL. This means, among other things, that every RewriteRule gets checked again.

在你的情况,发生的事情是,你从浏览器访问 /索引/ X / Y / 。在的.htaccess 文件触发的最后一条规则,即改写为 /index.php?id=X&cat=Y ,以便Apache有可能创造一个新的内部子请求的URL /index.php?id=X&cat=Y 。符合您前面外部重定向规则,以便Apache发送一个302响应返回给浏览器重定向到 /索引/ X / Y / 。但要记住,浏览器就不会看到内部子请求;只要它知道,它已经在 /索引/ X / Y / 。所以看起来你好像你正在从重定向 /索引/ X / Y / 来的同一网址,引发无限循环。

In your case, what happens is that you access /index/X/Y/ from the browser. The last rule in your .htaccess file triggers, rewriting that to /index.php?id=X&cat=Y, so Apache has to create a new internal subrequest with the URL /index.php?id=X&cat=Y. That matches your earlier external redirect rule, so Apache sends a 302 response back to the browser to redirect it to /index/X/Y/. But remember, the browser never saw that internal subrequest; as far as it knows, it was already on /index/X/Y/. So it looks to you as though you're being redirected from /index/X/Y/ to that same URL, triggering an infinite loop.

除了性能影响,这可能是更好的原因,你应该避免将重写规则的.htaccess 文件时可能之一。如果将这些规则到主服务器的配置,你不会有这样的问题,因为对规则进行匹配,将不会触发内部子请求。如果您没有访问主服务器配置文件,一个办法可以围绕它得到(修改的:我这样想着,虽然它似乎没有工作 - 看评论)是由加入 [NS] (无子请求)标志,以你的外部重定向规则,

Besides the performance hit, this is probably one of the better reasons that you should avoid putting rewrite rules in .htaccess files when possible. If you move these rules to the main server configuration, you won't have this problem because matches on the rules won't trigger internal subrequests. If you don't have access to the main server configuration files, one way you can get around it (EDIT: or so I thought, although it doesn't seem to work - see comments) is by adding the [NS] (no subrequest) flag to your external redirect rule,

RewriteRule ^index\.php$ http://example.com/index/%1/%2/? [L,R,NS]

一旦你这样做,你应该不再需要来检查的第一个规则的 REDIRECT_STATUS

这篇关于为什么这导致无限循环的要求?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆