乱码问题解决之道

关键词:乱码 Ajax XMLHttpRequest send JSP Java JavaScript JScript UTF-8 GB2312 UNICODE

乱码的意思就是混乱的编码,也就是编码错误导致的问题,我们可以把编码划分成以下三个环节:

1) 发送方对信息编码

2) 发送编码后的信息给接收方

3) 接手方采用什么编码分析接收到的信息

(此处发送方和接收方应为广义的意义:B/S或C/S结构中,发送方可以是服务端或客户端,相应接收方就是客户端或服务端。当通过文件交换信息时,发送方是存储程序,接收方则是读取程序。)

出现乱码问题肯定是至少其中一个环节出现了问题,因此乱码问题解决之道就是从上面三个环节找原因,具体而言可以问下面三个问题:

a.       发送方的编码方式是什么

b.       发送方把编码方式告知接收方了吗

c.       接收方采用的编码方式是否正确

只要能清楚的回答这三个问题,乱码问题自然就迎刃而解,这就是乱码问题解决之道。

下面就具体的例子进一步阐述:

例子一:JSP页面显示时的中文乱码问题,文件如下:

<html>

<%@page contentType=”text/html”%>

<%=”你好!”%>

</html>

大部分文章对此都说把contentType增加charset=gb2312,那么果真如此吗?

遵循乱码问题解决之道,可以有3个问题:

a.       编辑这个文件的程序采用什么编码方式把文本存储到文件

b.       编辑程序如何通知文件读取程序

c.       文件读取程序采用什么编码打开

对照着理解,我们可以看出增加charset=gb2312潜在的三层意思:第一是认为文件肯定是gb2312编码存储的;第二是文件读取程序被通知文件采用的gb2312编码存储;第三是文件读取程序将采用gb2312编码打开。看出问题了吧?

认为文件肯定是gb2312编码存储的就犯了错误,如果有人不是以gb2312存储的,而是采用其它编码,并且和gb2312不兼容的话,那么加上charset=gb2312也没用,仍是乱码。弄清楚是什么编码再写charset才是真正解决方案,而不是简单的加上charset=gb2312

例子二:采用Ajax时,服务端收到的是乱码

在JavaScript代码中:

      alert(postString);          // 测试用

      ajax.send(postString);

其中postString是中文字符串,如“高兴”,ajax则是XMLHttpRequest实例(非IE),或ActiveXObject("Msxml2.XMLHTTP")的实例(IE)。

通过第一行的alert可以发现postString在send之前还能正常显示,但服务端

      String str=request.getParameter(“name”);

得到的str却是乱码。

遵循乱码问题解决之道,可以有3个问题:

a.       ajax.send对postString是否编码了?编码方式是什么?

b.       ajax通知服务端编码方式了吗?

c.       服务端是采用什么编码方式读取数据的?

第二个问题比较好回答,因为编码方式是通过Content-type中的charset传递的,在服务端代码中增加:

       System.out.println("Coding: " + request.getCharacterEncoding());

即可,经过打印,可以看到charset是gb2312,那么ajax.send果真是采用gb2312编码吗?

由于无法跟踪到ajax.send内部,因此只好从服务端想办法,在上面的服务端代码后面加上:

    for (i=0; i < str.length(); i++) {

       ch = str.charAt(i);

       System.out.print(ch);

       System.out.print(Integer.toBinaryString(ch));

       System.out.print(' ');

    }

把接收到的字符串以二进制显示出来,需要注意的是Java字符串是以UNICODE码形式存储的,因此此时打印出的是UNICODE二进制编码。经过调试,发现ajax发送的“书”字在服务端打印出来是“涔”,UNICODE码是“110110110010100”,这说明ajax.send并不是以gb2312编码发送数据的,否则在服务端根据gb2312读取的是“书”,UNICODE码是“100111001100110”。

等等,前面描述还有点问题J,里面还有个假设就是ajax发送的postString也是以UNICODE码存储的,然后通过send编码后发送出去。还好,这个假设是成立的J。开始我总想着postString是以gb2312存储的,结果费了很大劲。

既然ajax.send不是gb2312编码,那么就另换一种,把charset改成UTF-8,这次服务端打印出来正确的“书”,也打印出它的UNICODE码。这说明ajax.send是以UTF-8编码的。第一个问题终于得到回答。(在网上搜了半天,没有看到ajax.send关于采用UTF-8编码的官方文档,因此尝试了好多次。如果一开始知道,就不用费周折了)

通过charset=UTF-8,服务端也知道是UTF-8编码,从而能正确解析。第三个问题

总结一下:

l       Ajax乱码问题的关键原因是send()函数默认采用了UTF-8对待发送字符串编码。

l       JavaSscript和Java字符串中存储的都是UNICODE码

l       该例子的乱码问题与GB2312没有关系,把charset设置为GB2312不能解决问题

l       解决问题方式是服务端采用UTF-8编码读取send发来的数据,需要设置charset=UTF-8

l       期待send函数支持多种编码方式吧J

(以上JavaScript包括JScript)

例子三:表单提交后服务端得到乱码

<form action=”proc.jsp” method=”post”>

   <input type=”text” name=”instr” value=””>

   <input type=”submit” value=”提交”>

</form>

在instr中输入中文,发送到服务端proc.jsp得到乱码,proc.jsp代码

    str = request.getParameter("instr");

遵循乱码问题解决之道,可以有3个问题:

a.       表单提交的instr是否编码了?编码方式是什么?

b.       表单提交的数据包中明确编码方式了吗?

c.       服务端是采用什么编码方式读取数据的?

第一个问题自己清楚,例如我是以gb2312保存文件的,因此编码方式是gb2312

通过在服务端加上以下语句:

       System.out.println("Coding: " + request.getCharacterEncoding());

可以回答问题b,结果是null,这说明第二个环节出了问题。解决办法就是让表单提交的数据包中明确编码方式,也就是在form属性中增加:

       accept-charset = “gb

不过IE6.0以前版本(7不知道,没试过)不支持这个属性,因此只能采用跳过第二个环节,直接为服务端指定编码方式,这也是网上普遍给出的解决方案,在getParameter()之前加上:

       request.setCharacterEncoding("gb2312");

当然也可以采用

str = new String(request.getParameter("instr").getBytes("iso-8859-1"), "gb2312");

即先按iso-8859-1编码读出,此时存储的是gb2312编码值,然后利用Java的String构造函数以gb2312解码字符串为UNICODE字符串存储,结果一样,不过稍显烦琐。

最后强调一句,网上很多人建议把网页文件采用UTF-8编码存储,其实没有必要,仍旧可以采用GB2312存储,在出现乱码问题时(或之前)问问上面的三个问题即可。

原文地址:https://www.cnblogs.com/elleniou/p/3177870.html