上周在微信项目中出现一个比较棘手的乱码问题,有一些解决心得跟大家分享:

 

一、问题

     首先肯定了几个事实:

     0、在/etc/sysconfig/i18n文件中设置linux系统编码格式:LANG=en_US.UTF-8

1、  微信关注回消息,格式肯定是UTF-8。

2、  微信项目编码格式是UTF-8

3、  项目的过滤器、拦截器等都设置为UTF-8

4、  在response对象返回时,设置了编码格式为UTF-8,即:response.setCharacterEncoding(“UTF-8”);

5、  在web工程向biz工程写入数据流时,也设置了UTF-8,即:BufferedWriter out = newBufferedWriter(new OutputStreamWriter(httpURLConnection.getOutputStream(),"UTF-8"));

6、  biz工程在读取数据流时也设置了UTF-8,即:BufferedReaderbr = new BufferedReader(new InputStreamReader((ServletInputStream)request.getInputStream(), "UTF-8"));

     ……

     问题出来了,即便做了上述设置,写入到数据库依然是乱码,于是开始怀疑是数据库编码格式不对,经查,发现SQL Server确实不支持UTF-8的数据,查看SQLServer的方式如下:

SELECT COLLATIONPROPERTY('Chinese_PRC_Stroke_CI_AI_KS_WS', 'CodePage')

        936 简体中文GBK 
950 繁体中文BIG5 
437 美国/加拿大英语 
932 日文 
949 韩文 
866 俄文 
65001 unicode UFT-8

936”,说明SQLServer确实是GBK格式。

 

      那怎么才能解决呢?

 

二、解决方案

    1、尝试转码

newString(str.getBytes("GBK"), "UTF-8");

      结果失败!

   2、尝试以GBK写入数据流,再以GBK读出数据流

      结果失败!

   3、通过中间格式ISO-8859-1过渡转换

结果失败!

   4、修改数据库驱动的编码格式:

DBUrl=jdbc:sqlserver://10.140.129.11:64013;useUnicode=true&characterEncoding=GBK;DatabaseName=wxtest

是否在系统层面出了问题。

   5、使用locale命令查看系统语言环境变量,发现环境变量又变回了zh_CN.GB2312,于是深究其原因,发现了如下线索:

      原来,linux设置语言环境变量时,有多个参数可以设置:LANG,LC_*,LC_ALL,且其优先级顺序为:

                  LC_ALL > LC_* >LANG

      因此设置了LANG变量还不够,可能会被LC_ALL覆盖掉,也就是说虽然看起来是在UTF-8环境中运行,但实际上还是运行在在GBK环境!!因此在/etc/sysconfig/i18n文件中设置了LC_ALL= en_US.UTF-8(注意设置完成后要重启)。

6、  Unicode转码

因为我们在第4条中设置了userUnicode=true,JAVA虚拟机都是以unicode的方式在内存中运行,因此在写入对象中调用了Unicode2GBK的方法转码,然后写入到数据库,一切正常!具体方法参见:


 

 

   以上是解决乱码的全过程,可能有些方案还没测试到(如同时去掉unicode连接和unicode转码),但我们日常项目中遇到的乱码问题,不外乎上述涉及的内容,以此分享之,希望能对大家有所帮助。