最近遇到一些apache配置问题,需要做这样一个需求,进来的url里面有带了版本号的信息,例如v123这样的,需要根据这个信息设置一个服务器环境变量,然后代码中读取这个变量以确定当前版本,做一些逻辑。一开始想到的方案是用apache的setEnvIf指令,用正则匹配URI中的v123,然后设置到环境变量中去
SetEnvIf Request_URI "^/(v[0-9]+)/.*" VERSION=$1
这样我就可以在代码中用$_SERVER['VERSION']来读到当前请求的版本信息,一开始work得挺好
后来有个问题,有另一种链接,它的版本号信息是带在get参数里的,这个VERSION的值一直是空的,查了官网发现有这么一句
Request_URI 在HTTP请求行中请求的资源(通常是URL中去除协议、主机以及查询字符串后剩余的部分)。
于是,在SetEnvIf这个指令里,这个Request_URI并不是apache通常指的那个uri,它是url里去掉域名和QUERY_STRING的那部分,然后这个指令就搞不定了。然后我就试了一下SetEnvIf里能不能直接用QUERY_STRING去匹配呢?结果是不行,应该是这个指令不支持跟QUERY_STRING的匹配
然后我想到在rewrite规则里是可以对QUERY_STRING做匹配的,于是我就想能不能先做一次rewrite,在rewrite里面取到get参数里的版本号信息,重写url,让新的url里面带上版本号信息,然后执行SetEnvIf指令的时候不就能取到版本号信息了么?这个想法太完美啦!
RewriteEngine on
RewriteCond %{REQUEST_URI} ^/redirect.*
RewriteCond %{QUERY_STRING} ^.*(v[0-9]+).*
RewriteRule /redirect.php /%1/redirect.php
SetEnvIf Request_URI "^/(v[0-9]+)/.*" VERSION=$1
也就是说如果请求是mydomain/redirect开头的请求,我就去它的query_string里面找v123的版本信息,然后把这个请求重定向到mydomain/v123/redirect...这里去
结果事实证明我太天真了,rewrite规则是生效了,也重定向到了正确的页面,但是$_SERVER['VERSION']这个变量的值仍然是空的。推测是这样的,apache的一次请求就做一次环境变量的设置,在重定向的时候是不会根据新的url执行SetEnvIf指令的
然后又是各种搜索,终于发现在RewriteRule里面有一个设置环境变量的参数
15. 'env|E=VAR:VAL' (设置环境变量)
设置名为VAR的环境变量的值为VAL,其中VAL中可以含有正则式的后向引用($N或%N)。这个标志可以使用多次,以设置多个环境变量。这儿设置 的变量,可以在多种情况下被引用,如在XSSI或CGI中。另外,也可以在RewriteCond模板中以%{ENV:VAR}的形式被引用。
这样就可以只针对版本号信息在get参数的情况做一个rewrite规则的同时设置一下环境变量就好啦
RewriteEngine on
RewriteCond %{REQUEST_URI} ^/redirect.*
RewriteCond %{QUERY_STRING} ^.*(v[0-9]+).*
RewriteRule /redirect.php /redirect.php [E=VERSION:%1]
SetEnvIf Request_URI "^/(v[0-9]+)/.*" VERSION=$1
搞定!这样就可以在代码里顺利取到VERSION的值啦。但是文中还有一句“这个标志可以使用多次,以设置多个环境变量”,但是这多个环境变量要怎么设置呢?只好自己试一试了,最后还真的被我试出来了
RewriteEngine on
RewriteCond %{REQUEST_URI} ^/redirect.*
RewriteCond %{QUERY_STRING} ^.*(v[0-9]+).*
RewriteRule /redirect.php /redirect.php [E=VERSION:%1,E=ABC:%1/others]
SetEnvIf Request_URI "^/(v[0-9]+)/.*" VERSION=$1
这样我就可以取到2个环境变量的值了,搞定!
主要参考文档:
apache中文帮助:http://man.chinaunix.net/newsoft/ApacheMenual_CN_2.2new/mod/mod_rewrite.html