上周在微信项目中出现一个比较棘手的乱码问题,有一些解决心得跟大家分享:
一、问题
首先肯定了几个事实:
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转码),但我们日常项目中遇到的乱码问题,不外乎上述涉及的内容,以此分享之,希望能对大家有所帮助。