您的位置:首页 > 运维架构 > Tomcat

中文乱码解决方案

2010-06-24 09:38 507 查看
<!--
/* Font Definitions */
@font-face
{font-family:宋体;
panose-1:2 1 6 0 3 1 1 1 1 1;
mso-font-alt:SimSun;
mso-font-charset:134;
mso-generic-font-family:auto;
mso-font-pitch:variable;
mso-font-signature:3 135135232 16 0 262145 0;}
@font-face
{font-family:"Cambria Math";
panose-1:2 4 5 3 5 4 6 3 2 4;
mso-font-charset:0;
mso-generic-font-family:roman;
mso-font-pitch:variable;
mso-font-signature:-1610611985 1107304683 0 0 159 0;}
@font-face
{font-family:"Arial Unicode MS";
panose-1:2 11 6 4 2 2 2 2 2 4;
mso-font-charset:134;
mso-generic-font-family:swiss;
mso-font-pitch:variable;
mso-font-signature:-134238209 -371195905 63 0 4129279 0;}
@font-face
{font-family:Calibri;
panose-1:2 15 5 2 2 2 4 3 2 4;
mso-font-charset:0;
mso-generic-font-family:swiss;
mso-font-pitch:variable;
mso-font-signature:-1610611985 1073750139 0 0 159 0;}
@font-face
{font-family:"/@宋体";
panose-1:2 1 6 0 3 1 1 1 1 1;
mso-font-charset:134;
mso-generic-font-family:auto;
mso-font-pitch:variable;
mso-font-signature:3 135135232 16 0 262145 0;}
@font-face
{font-family:"/@Arial Unicode MS";
panose-1:2 11 6 4 2 2 2 2 2 4;
mso-font-charset:134;
mso-generic-font-family:swiss;
mso-font-pitch:variable;
mso-font-signature:-134238209 -371195905 63 0 4129279 0;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
{mso-style-unhide:no;
mso-style-qformat:yes;
mso-style-parent:"";
margin:0cm;
margin-bottom:.0001pt;
text-align:justify;
text-justify:inter-ideograph;
mso-pagination:none;
font-size:10.5pt;
mso-bidi-font-size:11.0pt;
font-family:"Calibri","sans-serif";
mso-fareast-font-family:宋体;
mso-bidi-font-family:"Times New Roman";
mso-font-kerning:1.0pt;}
.MsoChpDefault
{mso-style-type:export-only;
mso-default-props:yes;
font-size:10.0pt;
mso-ansi-font-size:10.0pt;
mso-bidi-font-size:10.0pt;
mso-ascii-font-family:Calibri;
mso-fareast-font-family:宋体;
mso-hansi-font-family:Calibri;
mso-font-kerning:0pt;}
/* Page Definitions */
@page
{mso-page-border-surround-header:no;
mso-page-border-surround-footer:no;}
@page Section1
{size:595.3pt 841.9pt;
margin:72.0pt 90.0pt 72.0pt 90.0pt;
mso-header-margin:42.55pt;
mso-footer-margin:49.6pt;
mso-paper-source:0;
layout-grid:15.6pt;}
div.Section1
{page:Section1;}
/* List Definitions */
@list l0
{mso-list-id:1608925745;
mso-list-template-ids:629205626;}
@list l0:level1
{mso-level-tab-stop:36.0pt;
mso-level-number-position:left;
text-indent:-18.0pt;}
@list l1
{mso-list-id:1748769821;
mso-list-template-ids:-925629664;}
@list l1:level1
{mso-level-tab-stop:36.0pt;
mso-level-number-position:left;
text-indent:-18.0pt;}
@list l2
{mso-list-id:1870676537;
mso-list-template-ids:-1979043108;}
@list l2:level1
{mso-level-tab-stop:36.0pt;
mso-level-number-position:left;
text-indent:-18.0pt;}
@list l3
{mso-list-id:1976569749;
mso-list-template-ids:-268377040;}
@list l3:level1
{mso-level-tab-stop:36.0pt;
mso-level-number-position:left;
text-indent:-18.0pt;}
ol
{margin-bottom:0cm;}
ul
{margin-bottom:0cm;}
-->

IE6
的“

以UTF-8

发送URL”

选项设置对请求页面字符编码有影响吗?



关键字:
字符编码

     
最近又碰到了中文乱码问题,这里我没有把数据库牵扯进来,先说下我的环境,servlet
容器使用Tomcat6.0
,浏览器FireFox3.0
、IE6
,涉及字符编码设置的地方我的思路就是编码的地方都统一使用UTF-8
,具体配置如下:

1.
所有页面的charset
设置为UTF-8


2.Tomcat
的URIEncoding
默认是ISO-8859-1
,而我设置为UTF-8
,主要是想解决中文命名的文件以及请求以get
方式提交有可能出现的乱码问题。

3.
添加过滤器,调用request.setCharacterEncoding("utf-8")
方法将request
的字符集设定为utf-8
,解决请求以post
方式提交的乱码问题。

其实这样的设置貌似是不会再出现乱码问题了,不过,问题依旧来了

,如果我在浏览器的地址栏中输入中文参数提交,返回的页面却出现了乱码。真搞不明白到底是哪里出了问题!说起来对中文乱码的问题一直是一支半解,出现乱码了,网上搜罗了一大堆资料,按照网上的配置,问题到是解决了,不过原理却搞的很模糊,一个请求发送到服务器,服务器业务逻辑处理后返回一个页面,这中间涉及的字符集转换,编码,解码过程一概不清楚。这次,折腾了半天,总算是更进一步了解了字符编码问题,这里做个总结。

先看我的总结,
有不对的地方欢迎批评。

首先我们看下,一个请求响应的流程

 

浏览器 IE/FireFox -------->Servlet
容器----------------->
显示页面

      
编码          
使用容器的URIEncoding
转码
            
解码

我把用户发送请求方式不同引起的中文问题划分了四种类型:

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
代码

new String(
变量值.getBytes("UTF-8"),"ISO-8859-1");  

new String(
变量值.getBytes("UTF-8"),"ISO-8859-1");

根据API
的解释,先将变量值以UTF-8
字符集编码转换为字节序列,再以ISO-8859-1
字符集解码字节数组,构造出新的字符串对象。

等价于以下方式:

Java
代码

String code = "
编码";   

code = URLEncoder.encode(code,"UTF-8");
  

code = URLDecoder.decode(code,"ISO-8858-1");  

String code = "
编码";

code =
URLEncoder.encode(code,"UTF-8");

code =
URLDecoder.decode(code,"ISO-8858-1");

 

例如表单的username
属性以字符串"
编辑"
提交,那么进入容器后,FormBean
中的这个变量会乱码,request.getParameter(username)
一样的效果,s1
就是request
返回的结果,下面是内存快照。

不过即使这样,我们依然可以使用不恰当的方法显示正常的中文,即逆向转码,例如上面的乱码,我们可以通过ISO8859-1-->UTF-8
这种方式还原我们提交时的中文。以下是GBK
,UTF-8
,ISO-8859-1
三者之间互相转换的内存快照:

 
我们可以看到,偶数汉字可以在UTF-8
,GBK
两者中互相转换,而奇数个汉字则不能。综上看来,貌似Tomcat
的URIEncoding
设置为UTF-8
是最好的解决办法,不过这样的设置依然无法解决上面我所说的第三、第四种情况。大家继续向下看。(
这里有一点我不确定,就是页面提交至Servlet
容器时,是以页面的charset
方式编码后直接进入容器,还是以charset
转码为ISO-8859-1
方式进入,大家有什么见解?)
2.

表单的post
提交


对于这种方式的请求,request.setCharacterEncoding("
一般来自于web.xml
中过滤器设置的参数")
方法进行编码设置将会产生作用,struts
的表单提交方式默认为post
方式,那么按照上面我的环境设置,页面,容器,都采用UTF-8
编码方式,就不会产生中文乱码问题。
3.

页面链接中传递中文参数

我虚拟一个这样的场景,请求页面中有如下代码

Html
代码

<

%   

String username
 = "

编辑"

;   

%>

  

<a

 href
="hello.do?username=<%=username%>"
>


页面中链接传递中文</a>

  

<%

String username = "
编辑";

%>

<a
href="hello.do?username=<%=username%>">
页面中链接传递中文</a>

对于这种方式,我们需要先将参数使用统一的编码方式编码,将编码后的字符放入链接,这里我对参数以UTF-8
方式编码,如下

Java
代码

<%
  

String username = java.net.URLEncoder.encode("
编辑","UTF-8");   

%>  

<%

String username =
java.net.URLEncoder.encode("
编辑","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”
选项设置对请求页面字符编码有影响吗?欢迎讨论!

 

我的测试代码共享给大家:),
使用的是struts1.2
,struts
的jar
包,大家可以去apache
下载。

 

这里推荐个链接,有兴趣的可以深入了解更多字符集、编码的问题。
http://hideto.javaeye.com/blog/97803
 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息