本文写于 12 年前(2013 年 12 月),部分内容可能已经过时。

今天遇到一个诡异的编码问题:我们这边一个客户端A调用某个网关B,网关调用某个服务C,服务C又调用服务D。结果发现收到的数据有中文乱码。但是这个乱码和用错编码的乱码很不同:大部分都是正确的,就是几个字符是乱码(基本都是’?’)。在A直接调用D,编码没有问题。说明A和D都是同一种编码(确定是utf-8编码)。那么就是中间的B和C编码出问题了。于是确定了一下B和C的编码,果然B是utf-8,C是GBK。C的编码与大家都不一致,所以会出现这个问题。

但是这里有个诡异的问题,就是在一个调用串中,即使每个调用方的编解码都是约定好的,只要这条调用串的编码不一致(而且是多字节编码方式的),就会出现乱码问题。看下面这个例子:

public class MultipleEncodingTest{

    public static void main(String[] args) throws UnsupportedEncodingException {
        String str = "广东5天内确诊第4例人感染H7N9病例";

        String encoding = "UTF-8";
        String intermediateEncoding = "GBK";

        System.out.println(str);

        // 发送前编码
        byte[] bs = str.getBytes(encoding);

        // 中间服务解码再編码
        str = new String(bs, intermediateEncoding);
        bs = str.getBytes(intermediateEncoding);

        // 接收端解码
        str = new String(bs, encoding);

        System.out.println(str);

    }
}    

打印结果:

广东5天内确诊第4例人感染H7N9病例
广东5天内确诊�?例人感染H7N9病例

如果把中间服务的编解码改成单字节的iso8859就不会有问题了:

String intermediateEncoding = "iso8859-1";


广东5天内确诊第4例人感染H7N9病例
广东5天内确诊第4例人感染H7N9病例

结论 多次编解码,一定要保证整个链条中的每个节点都是同样的编码,或者中间节点采用单字节的编解码方式(如iso8859-1)。

这篇对你有用?

本文由 arganzheng 创作,采用 CC BY 4.0 许可协议。在保留原文作者、署名以及完整原文链接(https://arganzheng.life/multiple-encoding-problem.html)的前提下,欢迎各种形式的转载、翻译或商业引用。


COMMENTS

评论存放在 GitHub Discussions, 用 GitHub 账号登录即可发表,支持 Markdown。 想针对正文某句话说?选中那段文字,点浮出的「评论」即可划线评论;觉得哪里写错了,发表时勾上「同时提交 Issue」。 有人回复你时 GitHub 会按你的通知设置发邮件,不用守在这里。

×