在当前的web应用中,js操作页面元素的情况越来越多,尤其是通过js发起异步请求时遇到编码问题的情况经常出现。下面介绍在js中出现编码问题的几种情况。
1.外部引入js文件
在一个单独的js文件中包含字符串输入的情况,如:
<html> <head> <script src="statics/javascript/script.js" charset="gbk"></script>
如果引入一个script.js脚本,这个脚本中有如下代码:
document.write("这是一段中文"); //document.getElementById('testid').innerHTML = '这是一段中文‘;
这时如果script没有设置charset,浏览器就会以当前和这个页面的默认字符集解析这个js文件,如果外部的js文件的编码格式与当前页面的编码格式一致,那么可以不设置这个charset。但是,如果script.js文件与当前页面的编码格式不一致,如script.js是UTF-8编码而页面又是GBK编码,上面代码中的中文输入就会变成乱码。
2.JS的URL编码
通过js发起异步调用的url默认编码也是受浏览器影响的,如使用原始ajax的http_request.open(‘GET‘,url,true)调用,URL的编码在IE下是操作系统的默认编码,而在FireFox下则是UTF-8编码。另外,不同的JS框架可能对URl编码处理也不一样。那么,如何处理JS的URL编码问题呢?
实际上,在JS中处理URL编码的函数有三个,只要掌握了这三个函数,基本上就能正确处理JS的URL乱码问题了。
1.escape()
这个函数是将ASCII字母、数字,标点符号(* + - . / @ _)之外的其他自负转化成Unicode编码值,并且在编码值前加上“%u“,如下图所示。
通过将特殊字符转换成Unicode编码值,可以避免因为编码的字符集不兼容而出现信息丢失问题,在服务端通过解码参数就可以避免乱码问题。
注意,escape()和unecape()已经从ECMAScript v3标准中删除了,URL的编码可以用encodeURI()和encodeURIComponent来代替。
2.encodeURI()
与escape()相比,encodeURI()是真正的JS用来对URL编码的函数,它可以将整个URL中的字符(一些特殊字符除外,如“!” "#" "$" "&" "‘" "(" ")" "*" "+" "," "-" "." "/" ":" ";" "=" "?" "@" "_" "~" "0-9" "a-z" "A-Z")进行UTF-8编码,在每个码值前加上“%”,如下图所示。
解码通过decodeURI函数,如下图所示。
3.encodeURICompoent()
encodeURIComponent()这个函数比encodeURI()编码还要彻底,它除了对"!" "," "(" ")" "*" "-" "." "_" "~" "0-9" "a-z" "A-Z" 这几个字符不编码,对其他所有字符都编码。这个函数通常用于将一个URL当作一个参数放在另一个URL中,如下图所示。
它可以将HTTP://localhost/servlet/君山?a=c&a=b 作为一个参数放在另一个URL中,如果不进行encodeURIComponent()编码,后面URL中的“&”将会影响前面的URL的完整性。通过decodeURIComponent()进行编码,如下图所示。
4.java与js遍解码问题
前面所说的三个函数都是JS来处理的,如果JS进行了编码,编码的字符传到服务端后可以Java来解码,那么Java又是怎么解码的呢?
我们知道,在Java端处理URL编解码有两个类,分别是java.net.URLEncoder和java.net.URLDecoder。这两个类可以将所有"%"加UTF-8码值用UTF-8解码,从而得到原始的字符。查看URLEncoder的源码你可以发现,URLEncoder受保护的特殊字符要少于在JS中受保护的特殊字符。Java端的URLEncoder和URLDecoder与前端JS对应的是encodeURIComponent和decoderURIComponent。注意,前端用encodeURIComponent编码后,到服务端用URLDecoder解码可能会出现乱码,这一定是两个字符编码不一致导致的。JS编码默认的是UTF-8编码,而服务端中文解码一般都是GBK或者GB2312,所以用encodeURIComponent编码后是UTF-8,而Java用GBK去解码显然不对。解决的办法是用encodeURIComponent两次编码,如encodeURIComponent(encodeURIComponent(str))。这样在Java端通过request.getParamter()用GBK解码后取得的就是UTF-8编码的字符串,如果Java端需要使用这个字符串,则再用UTF-8解码一次;如果是将这个结果直接通过JS输出到前端,那么这个UTF-8字符串可以直接在前端正常显示。