mod_rewrite的正则表达式(过多的重定向)重定向、正则表达式、mod_rewrite

2023-09-02 11:40:12 作者:ヅ失溫℡

我使用的mod_rewrite ,以子域转换成目录下的网址。 (从这里解决方案)。当我明确地写一个子域的规则,它完美的作品:

I am using mod_rewrite, to convert subdomains into directory urls. (solution from here). When I explicity write a rule for one subdomain, it works perfectly:

RewriteCond %{HTTP_HOST}   ^[www.]*sub-domain-name.domain-name.com [NC]
RewriteCond %{REQUEST_URI} !^/sub-domain-directory/.*
RewriteRule   ^(.*)  /sub-domain-directory/$1  [L]

不过,如果我尝试匹配所有子域,它导致500内部错误(日志中说,过多的重定向)。在code是:

However, if I try to match all subdomains, it results in 500 internal error (log says too many redirects). The code is:

RewriteCond %{HTTP_HOST}   ^[www.]*([a-z0-9-]+).domain-name.com [NC]
RewriteCond %{REQUEST_URI} !^/%1/.*
RewriteRule   ^(.*)  /%1/$1  [L]

任何人都可以提出什么地方出了错,以及如何解决它?

Can anyone suggest what went wrong and how to fix it?

推荐答案

由于没有变你的第二个RewriteCond指令将永远不会返回假的,因为你可以在分析过程中测试的条款不使用反向引用(他们正在编制,使这个不可能的扩张将发生)。你实际上是在测试以便与文字文本 /%开始的路径1 / ,这是不是你想要的。既然你在每个目录范围内正在运行的规则集将最终会被再次应用,从而导致类似下面的转换:

Your second RewriteCond will never return false, because you can't use backreferences within your test clauses (they're compiled during parsing, making this impossible since no variable expansion will take place). You're actually testing for paths beginning with the literal text /%1/, which isn't what you wanted. Given that you're operating in a per-directory context, the rule set will end up being applied again, resulting in a transformation like the following:


path -> sub/path
sub/path -> sub/sub/path
sub/sub/path -> sub/sub/sub/path
...

这正好为约10次重复之前的服务器被打乱,并抛出一个500错误。有几种不同的方式来解决这个问题,但我会选择一个最接近你试图采取的办法。我还修改了第一次的RewriteCond,由于正前pression是有点瑕疵:

This goes on for about ten iterations before the server gets upset and throws a 500 error. There are a few different ways to fix this, but I'm going to chose one that most closely resembles the approach you were trying to take. I'd also modify that first RewriteCond, since the regular expression is a bit flawed:

RewriteCond %{HTTP_HOST}       ^([^.]+).example.com$ [NC]
RewriteCond %1                !=www
RewriteCond %1#%{REQUEST_URI} !^([^#]+)#/1/
RewriteRule .* /%1/$0 [L]

首先,它会检查HTTP_HOST值并捕获子域,不管它可能是。然后,假设你不希望这种转变发生在WWW的情况下,可确保拍摄不匹配。在此之后,它用常规的前pression自身的内部反向引用,看是否REQUEST_URI始于子域值。如果不是这样,它prepends子域作为目录,就像你现在。

First, it checks the HTTP_HOST value and captures the subdomain, whatever it might be. Then, assuming you don't want this transformation to take place in the case of www, it makes sure that the capture does not match that. After that, it uses the regular expression's own internal backreferences to see if the REQUEST_URI begins with the subdomain value. If it doesn't, it prepends the subdomain as a directory, like you have now.

这种方法的潜在问题是,如果你访问与作为子域的请求被发送到,喜欢的 sub.example.com/sub / 。另一种方法是检查REDIRECT_STATUS环境变量,看一个内部重定向已被执行(即,此prepending步骤已经发生):

The potential problem with this approach is that it won't work correctly if you access a path beginning with the same name as the subdomain the request is sent to, like sub.example.com/sub/. An alternative is to check the REDIRECT_STATUS environment variable to see if an internal redirect has already been performed (that is, this prepending step has already occurred):

RewriteCond %{HTTP_HOST}           ^([^.]+).example.com$ [NC]
RewriteCond %1                     !=www
RewriteCond %{ENV:REDIRECT_STATUS}  =""
RewriteRule .* /%1/$0 [L]