1. 匹配所针对的URL部分
mod_rewrite的RewriteRule语法为:
RewriteRule Pattern Substitution [flags]
其中在Virtual Host中Pattern只匹配host和port之后的部分,query string也不属于匹配范围,例如,请求URL为http://www.mydomain.com:8080/myaction?param=123,那么pattern只针对/myaction这部分内容。
Substitution 用来替换成功匹配的URL;Flags是一些控制匹配的标志,标志之间用逗号隔开,例如R表示跳转(Redirect),L表示规则终止(Last)。
例如, 有如下的匹配规则:
RewriteRule ^/$ /default/myaction [R,L]
若请求URL为http://www.mydomain.com:8080/myaction?param=123,那么经过mod_rewrite会跳转(通过标志R)到http://www.mydomain.com:8080/default/myaction?param=123。注意,这里的query string完好无损。
2. 附加查询字符串标志(QSA)
如果现在需要在跳转的URL中添加一个查询参数userid=1,该怎么办?
首先看规则这样写行不行:
RewriteRule ^/$ /default/myaction?userid=1 [R,L]
答案是:不可以。如果这样写的话,跳转的URL会变成http://www.mydomain.com:8080/default/myaction?userid=1,注意这里把原始的查询参数param=123给丢掉了。
正确的写法是使用QSA标志:
RewriteRule ^/$ /default/myaction?userid=1 [QSA,R,L]
这样QSA标志表示在用户添加的查询参数后附加原有的查询参数,即跳转的URL为:http://www.mydomain.com:8080/default/myaction?userid=1¶m=123。
3. 一个完整的例子
问题:如果用户输入的URL为http://www.mydomain.com:8080?phone=123,那么自动跳转到http://www.mydomain.com:8080/default/myaction_phone?company=1&phone=123;如果用户输入的URL为http://www.mydomain.com:8080,那么自动跳转到http://www.mydomain.com:8080/default/myaction?company=1。这里第一个跳转URL执行操作是myaction_phone,第二个跳转URL执行的操作是myaction。
答案:在Apache的虚拟主机配置中,可以这样写:
RewriteEngine on
RewriteCond %{QUERY_STRING} ^phone
RewriteRule ^/$ /default/myaction_phone?company=1 [QSA,R,L]
RewriteRule ^/$ /default/myaction?company=1 [R,L]
在这个配置中,RewriteCond只适用带QSA的第一条规则,因为这是规则链中的第一条也是最后一条规则(通过L标志),也就是说,只要查询字符串以phone开头,就应用第一条规则。如果用户请求的URL不满足RewriteCond的条件,就使用第二条规则。
4. 总结
下面一段引用自Apache mod_rewrite文档(http://httpd.apache.org/docs/current/mod/mod_rewrite.html#rewriterule)中的一段话,这段话基本上概括了mod_rewrite如何处理query string的问题:
Modifying the Query String
By default, the query string is passed through unchanged. You can, however, create URLs in the substitution string containing a query string part. Simply use a question mark inside the substitution string to indicate that the following text should be re-injected into the query string. When you want to erase an existing query string, end the substitution string with just a question mark. To combine new and old query strings, use the [QSA]
flag.