参考资料:http://blog.csdn.net/lfsf802/article/details/7232834
http://www.ruanyifeng.com/blog/2010/02/url_encoding.html
http://blog.csdn.net/howlaa/article/details/12834595
我把用户发送请求方式不同引起的中文问题划分了四种类型:
1、表单的get提交
2、表单的post提交
3、页面链接传递中文参数
4、地址栏中参数直接输入中文提交
1.首先我们看表单get方式提交
浏览器根据页面的charset编码方式对页面进行编码,然后提交至服务器,首先进入对应的字符编码过滤器(如果有的话),不过Tomcat6.0对于get提交方式采用的是server.xml文件中的URIEncoding编码方式,而并不会采用过滤器中设置的编码,那么根据我的环境设置,jsp页面都使用UTF-8的编码,Servlet容器的URIEncoding也设置为UTF-8,则servlet不用进行转码即可正确解码,获得正常的中文字符串。那么,响应页面的中文因为页面的统一编码(UTF-8)自然也会正常显示。当然,如果我们Tomcat的URIEncoding设置为其他非UTF-8的编码方式时,页面的内容进入Tomcat解析时,因为Tomcat和页面的编码不统一,就需要转码。例如,如果我们采用Tomcat默认的ISO-8859-1,那么当我们使用request.getParameter("yourVariable")获取表单参数值时其实Servlet就进行了转码,它会以容器编码方式进行解码,这个过程如下:
UTF-8(编码)-->ISO-58859-1(解码)
这个过程也相当于我们使用如下的语句
Java代码
2.表单的post提交
对于这种方式的请求,request.setCharacterEncoding("一般来自于web.xml中过滤器设置的参数")方法进行编码设置将会产生作用,struts的表单提交方式默认为post方式,那么按照上面我的环境设置,页面,容器,都采用UTF-8编码方式,就不会产生中文乱码问题。
3.页面链接中传递中文参数
说明:1、Java中的request.getParameter(String)方法会进行一次URI的解码过程,默认以ISO8859-1编码方式解码。
2、js发送请求的时候浏览器会对其进行一次URL编码,不管js自己有没有用encodeURIComponent来编过
(1)对于浏览器发出的HTTP请求:
URL: addressgrp.action?oper=addgrp&groupname="+encodeURIComponent(groupsname)
在action获取 groupname( getGroupname() )时并没有进过编码转化,获取的信息并不正确,经过尝试发现需要进行一次编码转换:
String grpname= new String(getGroupname().getBytes("ISO-8859-1"), "UTF-8");
在网上搜索相关的信息,网上提供了另一种方法:在页面上进行两次编码操作,然后在后台再进行一次解码,这是由于java后台在获取数据时已经进行了一次解码,可问题是进行一次解码后的数据并不正确,而如果在页面中编码两次然后在后台进行一次解码就可以获取真确的数据。页面URL:addressgrp.action?oper=addgrp&groupname="+ encodeURIComponent(encodeURIComponent(groupsname))
后台获取数据: String grpname =java.net.URLDecoder.decode( getGroupname() ,"UTF-8")
(2)对于Javascript发出的HTTP请求:
浏览器会对其再进行一次URL编码,那么直接在URL中接上中文字相当于(1)中的进行一次编码,那么后台通过
String grpname= new String(getGroupname().getBytes("ISO-8859-1"), "UTF-8");就可以获得到正确的结果。如果是javascript中主动对其进行了一次编码,加上浏览器自动的一次URL编码,那么相当于上述情况下两次编码操作,后台需要通过
String grpname =java.net.URLDecoder.decode( getGroupname() ,"UTF-8")来获得正确的中文数据。
总的来说,上述两种方式能够较好的解决中文乱码的问题了。
4.地址栏中参数直接输入中文提交
例如浏览器地址栏中输入"http://localhost:8080/helloapp.do?username=编辑"提交,对于这种方式,浏览器不会采用页面的charset方式对URL中的中文进行编码后提交至服务器(IE,FireFox都一样),而是采用系统的GBK转码为ISO-8859-1之后提交至Servlet容器,那么,如果对于前三种方式我们所做的设置,在这里就有问题了,因为进入容器时中文进行了GBK至ISO-8859-1的转码,而之前我们的Servlet容器URIEncoding设置为UTF-8,当我们使用request.getParameter("username")时,相当于又进行了这样的流程GBK-->ISO-8859-1-->UTF-8,按照以上我们使用的测试中文,“编辑”,使用request.getParameter("username")则会得到这样的结果�༭,下图是进行转码的内存快照:
我们可以看到
“编辑”经过从GBK-->ISO-8859-1-->UTF-8的过程后得到的就是�༭这样的结果,这里我们还会想到那进行2次逆向转码看看,不过可惜的是,结果为“锟洁辑”。对于这种情况,我们的解决办法就是,Tomcat的URIEncoding采用默认的ISO-8859-1字符集,那么我们可以在程序中通过ISO-8859-1-->GBK这样不恰当的逆向转码方式得到正常的中文“编辑”,但这样的结果是,我们get请求方式的中文处理解决办法就需要改变。如,在我的环境下就需要进行ISO-8859-1-->UTF-8的转码,挺不爽。
综上,对于乱码问题,前三种方式是一般用户的请求方式,第四种属于非正常途径的请求方式,对于这种方式产生的问题我认为无法很好的解决,也不需要解决。我看到javaeye对于这样的情况就没有处理,不知道大家在自己的项目中是如何处理的?我的实验是,IE6的设置会影响应用路径的编码方式,例如地址栏中请求一个中文JSP页面,如:http://localhost:8080/helloapp/编辑.jsp,IE默认是勾选"以UTF-8发送URL"项的,那么按照我上面总结的处理方式,这个请求可以正常显示页面,如图:
如果取消IE的这个选项,那么浏览器会以GBK编码应用路径的中文,得到的结果如图:
按照我上面的设置,这里如果将Tomcat的URIEncoding设置为GBK,则也可以正常显示页面。对于FireFox3.0,则是以UTF-8编码。
最后,回到我的题目,向大家讨教下,IE6的“以UTF-8发送URL”选项设置对请求页面字符编码有影响吗?欢迎讨论!