2

我们有以下重写规则:

 RewriteRule ^([A-Za-z0-9\_]+)$ index.php?rewrite=$1 [L,QSA]

我们想知道是否有一种方法可以让 ?rewrite=$1 优先于通过请求 uri 中的查询字符串传递的方法?

因为就目前而言,如果点击以下网址,则由于QSA 标志(我们确实需要它):

 http://www.domain.com/this_rewrite_will_match_the_above_rule?rewrite=some_value

PHP 中 $_GET['rewrite'] 的值将是some_value,而不是this_rewrite_will_match_the_above rule

在我们开始修改重写并添加 RewriteCond 以匹配查询字符串等之前...我们希望设置一个标志以便目标 url (index.php?rewrite=$1 在这种情况下)优先于传递的查询字符串值。

希望这是有道理的。

谢谢。

4

4 回答 4

2

有点骇人听闻

RewriteRule ^([A-Za-z0-9\_]+)$ index.php?%{QUERY_STRING}&rewrite=$1 [L]

这是有效的,因为在 php 中,第二个会rewrite=...覆盖第一个。

于 2012-12-09T21:05:58.020 回答
2

我已经搜索了一些机制来在 Apache 重写中多次且非常强烈地覆盖单个查询字符串参数,但看起来没有选择这样做,即使使用最新的 Apache 版本(撰写本文时为 2.4.3) .

但是还有一个替代方案,它利用了 PHP 查询字符串解析器仅返回多个相同查询字符串参数中的最后一个这一事实。

例子:

http://www.domain.com/index.php?id=123&id=456

这将在 $_GET 中返回以下单个 (!) 条目:

array(1) {
  ["id"]=>
  string(3) "456"
}

因此,您可以通过简单地将任何覆盖参数附加到现有查询字符串的末尾(而不在查询字符串中删除它们)来解决您的问题。重复参数的最后一次出现是使其进入 $_GET 数组的参数。

不幸的是,QSA 开关不适合这种技术,因为它总是将原始参数附加到新查询字符串的末尾。没有可以预先设置旧参数的开关。因此,您必须绕道而行,使用 RewriteCond 自己捕获并添加原始查询字符串,而不是使用 QSA:

RewriteCond  %{QUERY_STRING}  ^(.*)$
RewriteRule ^([A-Za-z0-9\_]+)$ index.php?%1&rewrite=$1 [L]

RewriteCond 的唯一功能是捕获 %1 中的查询字符串。条件的正则表达式(.*)总是匹配的,所以下面的 RewriteRule 总是被执行。

使用这种技术,您的上述测试用例将重写为...

http://www.domain.com/index.php?rewrite=some_value&rewrite=this_rewrite_will_match_the_above_rule

...这将由 PHP 查询字符串解析器解释为

$_GET["id"] => "this_rewrite_will_match_the_above_rule"

...这就是你想要的。

请注意,这仅在您从 PHP 的 $_GET 数组中获取查询字符串值时才有效。$_SERVER["QUERY_STRING"]如果您解析自己的内容或使用任何其他编程语言,它不一定会起作用。

于 2012-12-09T21:26:57.530 回答
2

我选择创建自己的答案,因为它比 Jpsy 和 Gerben 提供的示例稍微干净一些。

应得的信用,他们的建议是让我来到这里的原因,我只对它们进行了扩展:

因此,我们的最终解决方案包括 2 条规则。

# check if querystring is not empty (this is the addition vs other answers)
RewriteCond %{QUERY_STRING} !^$
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([A-Za-z0-9\_]+)$ index.php?%{QUERY_STRING}&rewrite=$1 [L]

如果上述查询字符串失败(主要是查询字符串为空),则将应用此规则。

RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([A-Za-z0-9\_]+)$ index.php?rewrite=$1 [L]

我选择进行这种双重规则设置的原因是为了避免在查询字符串为空时使 php 服务器变量被 "?&rewrite=...." 污染。

感谢 jpsy 和 gerben 的帮助。

于 2012-12-10T17:03:10.783 回答
0

我使用了以下说明:

RewriteRule ([^\?]*)\?(.*) $1?$2 [N]                          (1)
RewriteCond %{QUERY_STRING} (.*?)&?(rewrite=[^&]+)&?(.*)      
RewriteRule ^(.*)$ $1?%1&%3 [N]                               (2)
RewriteRule ^(.*)$ $1?domain=newValue [L,QSA]                 (3)

这个技巧是由前两个规则中的 [N] 标志完成的,这会导致重写引擎重新处理输出。

规则 (1) 简单地按原样重写 url。我需要它,因为我将 mod_rewrite 与 mod_proxy_ajp 一起使用,并且在第一次迭代中,查询字符串没有从 url 中拆分出来。第一行执行后,url 不变,但引擎将从查询字符串中拆分路径。

规则 (2) 迭代并从查询字符串中删除所有出现的参数“rewrite”。

规则 (3) 设置参数的新值,并附加任何从规则 (2) 完成的替换中幸存的查询字符串。

于 2014-08-14T08:28:18.227 回答