2011年10月26日

rewrite模块和connector的URIEncoding对url解析的影响

如果url中包含非ASCII字符(比如中文),W3C建议对url使用UTF-8编码并把编码后的每个byte用%HH的形式表示:比如"啊&啊""就被编码成"%E5%95%8A%26%E5%95%8A",使用java的话,就是调用URLEncoder.encode("啊&啊", "UTF-8")。

如果url是/?tag=%E5%95%8A%26%E5%95%8A,那么request.getQueryString()返回tag=%E5%95%8A%26%E5%95%8A,request.getParameter("tag")返回å•Š&å(在iso-8859-1环境下就是显示???&???)

根据api文档,getQueryString返回的是 String containing the query string or null if the URL contains no query string. The value is not decoded by the container.这是对的。

getParameter返回的是乱码,这也是对的,在上一篇日志中写过,"啊&啊"被tomcat用iso-8859-1编码了。

但是当url应用重写规则并给connector配置URIEncoding的时候,又会出现什么情况呢?

重写规则为了能匹配规则,会对url进行decode,connector的URIEncoding也会影响url的解析。

假设有这么个重写规则:RewriteRule ^/tag/(.)$ /tag.do?tag=$1 [PT,L]*
我在win7+apache2.2+tomcat6.0.29下,加上jboss的rewrite模块,针对 /tag/%E5%95%8A%26%E5%95%8A(需要被rewrite)和/?tag=%E5%95%8A%26%E5%95%8A(无需rewrite)

测试了各种条件下getQueryString和getParameter的返回值:

观察以上数据,可以看出:

  1. 在需要rewrite的时候:使用apache和jboss的rewrite模块,没有本质区别,经过rewrite后,getParameter得到的值都是一样的。唯一的不同是ajp的URIEncoding为"UTF-8"时,getQueryString返回的值不同。这是因为当使用jboss的rewrite模块时,"/tag/%E5%95%8A%26%E5%95%8A"被转为"/tag/啊&啊"后再rewrite,getQueryString就返回"tag=啊&啊了"。
  2. 在不需要rewrite的时候:apache通过ajp传给tomcat是"tag=%E5%95%8A%26%E5%95%8A",只要AJP Connector的URIEncoding为"UTF-8",getParameter就可以得到正确的值
  3. 由于url都是apache通过ajp传给tomcat,因此这里http connector的配置不起作用

再来看一下乱码,"啊"变成"???":字节信息还是正确的,通过new String(value.getBytes("ISO-8859-1"), "UTF-8")就能获取原来的值

在实践中可以遵循以下规则:

  1. 如果url由我们控制,就把url调用URLEncoder.encode(url, "UTF-8"),然后把对应的connector的URIEncoding设置成"UTF-8"(apache+tomcat就设置ajp,仅tomcat就设置http)。如果url经过rewrite,需要我们自己处理QueryString,否则直接getParameter即可。
  2. 如果url是根据用户输入产生,浏览器可能对url采用非UTF-8编码,此时最好不要对url做rewrite,并自己处理QueryString。