常见中文乱码问题

日常工作中,中文乱码算是比较常见的问题了,大家或多或少都遇到过。这里简单分析下我遇到过的乱码场景,错误和遗漏之处,欢迎大家补充、纠正和交流。

 

一、常见乱码问题

1.1 Ajax请求中文参数乱码

      发送Ajax请求时,如果参数中有中文,服务端获取到参数后,有可能乱码。

1.2 外联js代码中文字符乱码

      外联方式引入js文件,如果js的代码中有中文,有可能乱码。

下面就来依次分析这两个场景。

 

二、Ajax请求中文参数乱码

      Ajax请求分为GET和POST两种方式,对于这2种方式,Webx框架的处理不尽相同。此外,在客户端浏览器的处理上,也有可能出现一些中文编码字符集的不确定性。

 

     2.1 知识点

     首先介绍下encodeURIComponent('xxx'),这个js原生函数采用UTF-8编码,js代码中对中文字符进行显式编码时,基本上用的都是该函数。

     接下来介绍下编码的基本知识,在此copy一下Webx文档的一段话,如下。

alt

     2.1.1 GET请求

     对于GET方式的Ajax请求,如果未显式执行encodeURIComponent对中文参数进行编码,那么浏览器会根据“输出字符集”对中文字符进行编码,Webx默认配置的是GBK输出字符集,也就是说浏览器极有可能采用GBK字符集进行中文字符编码。当前,也不排除个别浏览器在实现上不是这个套路。如果使用了某些JS库的Ajax组件,JS库也有可能额外搞一些动作。而对于英文操作系统,由于我没有测试过,也不确定是否会影响到浏览器的编码字符集。因此存在着一定的编码字符集不确定性。

      在服务端对GET请求的处理过程中,Webx框架没有采用Servlet引擎的解码方式,而是另起炉灶,特殊进行了参数解析和字符解码。需要特别说明的是,Webx在此之前,统一设置了CharacterEncodingWebx默认配置的是GBK输入字符集GET请求参数解析和字符解码的关键代码如下图所示。

   alt

key = decode(key);
value = decode(value);

    详细代码可参见Webx3的com.alibaba.citrus.service.requestcontext.parser.impl.ParameterParserImpl类,以构造函数为入口进行阅读。

 

    2.1.2 POST请求

    对于POST方式的Ajax请求,字符编码一律采用UTF-8,这应该是Ajax的一个规范。在KISSY的代码和Webx的文档中都有阐述,Ajax规范还有待进一步研究确认。​

    对于非Ajax的正常表单提交,字符编码会采用web页面的字符集,对于淘宝的页面来讲,通常就是GBK。

    在服务端对POST请求的处理过程中,Webx框架采用了Servlet引擎提供的解码方式。仍然需要特别说明的是,Webx在Servlet引擎解码之前,也统一设置了HttpServletRequest的CharacterEncoding,即“输入字符集”,Webx默认配置的是GBK,与GET请求设置CharacterEncoding是在同一个地方。如下所示。

// 试图从queryString中取得inputCharset
String queryString = getRequest().getQueryString();
String inputCharset = locale.getCharset().name();
if (queryString != null) {
    Matcher matcher = inputCharsetPattern.matcher(queryString);
    if (matcher.find()) {
        String charset = matcher.group(1);
        if (LocaleUtil.isCharsetSupported(charset)) {
            inputCharset = charset;
        }
    }
}
getRequest().setCharacterEncoding(inputCharset);

详细代码可参见Webx3的com.alibaba.citrus.service.requestcontext.locale.impl.SetLocaleRequestContextImpl类,以prepare方法为入口进行阅读。

 

    2.2 乱码原因

    由以上知识点可知,我们通常遇到的乱码一般是由于客户端对中文采用了UTF-8编码,而服务端采用GBK解码导致。

 

    2.3 解决方法

    2.3.1 对于GET请求产生的乱码,通常需要做两件事情。第一,使用encodeURIComponent对中文字符进行编码,消除编码字符集的不确定性。第二,需要在url中额外增加 _input_charset 参数,值为UTF-8,这个参数是Webx预留的参数,可以优先设置本次请求的解码字符集,核心代码同2.1.2的代码贴图,这里补充一下webx.xml的配置和匹配_input_charset 参数的正则Pattern,如下所示。

<set-locale defaultLocale="zh_CN" defaultCharset="GBK" />
String INPUT_CHARSET_PARAM_DEFAULT = "_input_charset";

inputCharsetParam = defaultIfNull(inputCharsetParam, INPUT_CHARSET_PARAM_DEFAULT);
inputCharsetPattern = Pattern.compile(inputCharsetParam + "=([w-]+)");

    这里还有另外一种处理方式,即寻找第三方js库,提供GBK编码的encodeUri函数,可以免去url中的_input_charset 参数。

 

    2.3.2 对于POST请求产生的乱码,通常只需要在url(请注意是url,不是表单参数)中额外增加 _input_charset 参数,值为UTF-8即可。

    如果这样处理仍然有问题,并且使用的是KISSY库的Ajax组件,那么可以先使用encodeURIComponent对中文字符进行编码,然后再发送Ajax请求,这时候url中是否有_input_charset 参数已经无关紧要。之后,服务端业务代码要显式执行URLDecoder.decode("xxx","UTF-8"),即可获取到正确的中文字符。这里面发生了一些有趣的事情,简单YY下。在显式执行encodeURIComponent之后,发送Ajax请求之前,KISSY的Ajax组件又额外进行了一次encodeURIComponent。以“测试”举例,经过一次encodeURIComponent处理后的值是“测试,再经过一次encodeURIComponent,值变成了“%25E6%25B5%258B%25E8%25AF%2595,这样无论Webx框架采用何种输入字符集,Servlet引擎解码后,值都会恢复成“测试”,之后业务代码再显式执行URLDecoder # decode,就拿到中文字符了。

    KISSY额外的一次encodeURIComponent,发生在对传入的表单数组进行S.param的时候,可以参看源码。

 

三、外联js代码中文字符乱码

     3.1 知识点

     web页面引用外联JS,若未加特殊处理,一般会按照web页面的字符集对外联JS进行解码。

     浏览器解码的字符集,一般按照以下优先级判断。http header(”content-type:text/html; charset=xxx”)优先级最高,如http-header未指定则依据html <META http-equiv=”content-type” content=”text/html; charset=xxx”>,如果http-header和html-meta都没有指定,那么一般就是依据文件的BOM编码格式。

     3.2 乱码原因

     我遇到的乱码都是发生在daily环境。

     淘宝的web页面基本都是GBK字符集。

     淘宝外联的JS,daily环境放在assets测试服务器上,线上环境放在tbcdn上,编码字符集由JS文件的BOM决定。

     前端同学编写JS代码,在保存时一般都采用UTF-8编码。

     因此,用GBK解析UTF-8编码的中文字符,就出现乱码了。

     3.3 解决方法

     3.3.1 对script单独设置解码字符集,<script type=”text/javascript” src=”xxx.js” charset=”UTF-8″></script>,这样处理后,该script的解码就按照指定的charset进行。

     3.3.2 前端采用GBK字符集保存代码并提交。这个应该不太可行,前端采用UTF-8编码应该有一些原因,至于是对压缩有影响,还是其它的原因,有待深入探究。

     3.3.3 采用ucool等工具作代理,并将代理文件以GBK字符集保存。

     3.3.4 直接引用压缩之后的-min.js,这样会给debug带来困难,但肯定不会有乱码问题。因为淘宝使用的压缩工具,会将所有的中文字符替换成Unicode编码。因为线上引用的都是-min.js,所以就没有乱码问题。由此可见,压缩JS不单是缩短客户端下载时间,也能够避免乱码问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值