前言:
当jquery ajax在utf-8编码下(页面utf-8,接收utf-8),无任何问题。可以正常post、get,处理页面直接获取正确的内容。
但在以下情况下:
GBK -> AJAX POST ->GBK
UTF-8 -> AJAX POST ->GBK
后台代码无法获取正确的内容,通常表现为获取到奇怪字符、问号。
经典解决方法:
1:发送页面、接收页面均采用UTF-8编码。
2:发送页面在调用ajax post方法之前,将含有中文内容的input用encodeURIComponent编码一次,而接收页面则调用解码方法( 如:java.net.urldecoder.decode("接收到内容","utf-8") )。
其中,第一种方法无疑是最简单、最直接,但往往不符合实际,因为很多项目并不是使用utf-8编码,例如国内大部分使用gbk编码,也不可能为了解决这样一个问题,而将整个项目转换为utf-8编码,成本太大,风险太高。
第二方法,是现在最多人使用的方法,俗称二次编码,为什么叫二次编码,等下会解释。客户端编码两次,服务端解码两次。但这种方法不好的地方,就是前台手动编码一次,后台再手动解码一次,稍不留神就会忘记,而且代码掺和前台逻辑。
交互过程:
当我们使用表单按照传统方式post提交时候(非AJAX提交),浏览器会根据当前页面编码,encode一次,然后发送到服务端,服务端接收到表单,会自动dencode一次,通常这个过程是对程序是透明的,因此加上手动编码、解码,就变成上面所说的二次编码。
但当我们使用AJAX方式提交时候,浏览器并不会自动替我们encode,因此在jquery中有这样的一段代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
ajax:
function
( s ) {
// Extend the settings, but re-extend 's' so that it can be
// checked again later (in the test suite, specifically)
s = jQuery.extend(
true
, s, jQuery.extend(
true
, {}, jQuery.ajaxSettings, s));
var
jsonp, jsre = /=?(&|$)/g, status, data,
type = s.type.toUpperCase();
// convert data if not already a string
if
( s.data && s.processData &&
typeof
s.data !==
"string"
)
s.data = jQuery.param(s.data);
........
}
|
以上是jquery的ajax方法的代码片段,下面是正常调用jquery ajax post的代码:
1
2
3
4
5
6
7
8
9
10
|
$.ajax({
url: ajaxurl,
type:
'POST'
,
dataType:
'html'
,
timeout: 20000,
//超时时间设定
data:para,
//参数设置
success:
function
(html){
}
});
|
通过上面代码可以知道,当设置了data时候,jquery内部会调用jQuery.param方法对参数encode(执行本应浏览器处理的encode)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
jQuery.param=
function
( a ) {
var
s = [ ];
function
add( key, value ){
s[ s.length ] = encodeURIComponent(key) +
'='
+ encodeURIComponent(value);
};
// If an array was passed in, assume that it is an array
// of form elements
if
( jQuery.isArray(a) || a.jquery )
// Serialize the form elements
jQuery.each( a,
function
(){
add(
this
.name,
this
.value );
});
// Otherwise, assume that it's an object of key/value pairs
else
// Serialize the key/values
for
(
var
j
in
a )
// If the value is an array then the key names need to be repeated
if
( jQuery.isArray(a[j]) )
jQuery.each( a[j],
function
(){
add( j,
this
);
});
else
add( j, jQuery.isFunction(a[j]) ? a[j]() : a[j] );
// Return the resulting serialization
return
s.join(
"&"
).replace(/%20/g,
"+"
);
}
//jquery.param end
|
上面是jQuery.param的代码,细心点可以留意到encodeURIComponent这方法,这是javascript内置的方法,对目标字符串执行utf-8 encode,因此,当页面使用gbk编码时候,服务端会使用gbk进行解码,但实际提交的数据是以utf-8编码的,所以造成接收到内容为乱码或者为问号。
解决方法:
encodeURIComponent会以utf-8编码,在gbk编码下,可不可以以gbk进行编码呢?
如果还在打encodeURIComponent主意的话,那不好意思,encodeURIComponent只会utf-8编码,并没有其他api进行其他编码;不过,别担心,看看下面:
encodeURIComponent,它是将中文、韩文等特殊字符转换成utf-8格式的url编码。
escape对0-255以外的unicode值进行编码时输出%u****格式,其它情况下escape,encodeURI,encodeURIComponent编码结果相同。
哈哈,看到希望吧?没错,就是用escape代替encodeURIComponent方法,不过必须注意:
escape不编码字符有69个:*,+,-,.,/,@,_,0-9,a-z,A-Z
encodeURIComponent不编码字符有71个:!, ',(,),*,-,.,_,~,0-9,a-z,A-Z
使用了escape之后必须对加号进行编码,否则,当内容含有加号时候会被服务端翻译为空格。
终于知道解决办法了,重写jquery代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
jQuery.param=
function
( a ) {
var
s = [ ];
var
encode=
function
(str){
str=escape(str);
str=str.replace(/+/g,
"%u002B"
);
return
str;
};
function
add( key, value ){
s[ s.length ] = encode(key) +
'='
+ encode(value);
};
// If an array was passed in, assume that it is an array
// of form elements
if
( jQuery.isArray(a) || a.jquery )
// Serialize the form elements
jQuery.each( a,
function
(){
add(
this
.name,
this
.value );
});
// Otherwise, assume that it's an object of key/value pairs
else
// Serialize the key/values
for
(
var
j
in
a )
// If the value is an array then the key names need to be repeated
if
( jQuery.isArray(a[j]) )
jQuery.each( a[j],
function
(){
add( j,
this
);
});
else
add( j, jQuery.isFunction(a[j]) ? a[j]() : a[j] );
// Return the resulting serialization
return
s.join(
"&"
).replace(/%20/g,
"+"
);
}
|
上面那段代码并不需要在jquery的源文件重写,可以在你项目的javascript贴上,覆盖它原有的方法,不过必须在jquery加载之后。
经初步验证,上面那段代码在utf-8编码也可以工作正常,大概是编码成unicode的缘故吧。
这样,就不是需要使用什么二次编码,即影响前台,又影响后台。gbk编码下ajax post不再是问题了,此乃是终极解决方法。哈哈。
有兴趣的可以到http://www.open-lib.com/Forum/Read_69_1.action与作者交流。
作者你好,看到你的文章讲解的很详细,让初学者和第一次遇到这种问题的人都能够大致了解问题所在。
我的问题是,我在jsp页面贴上了你的jQuery.param函数。然后我在servlet获取参数的时候出现了报错:
System.out.println(request.getParameter("vals"));//执行这句的时候,出现了如下错误。
java.io.CharConversionException: isHexDigit
按楼主的文章所述,似乎没有提到servlet需要进行一些处理。还是楼主遗漏了。
还请楼主提示一些,偶还没懂。我的email是759063617@qq.com
QQ:759063617 感谢楼主的文章。
测试失败,请楼主指导一下:万分感谢!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
|
<html>
<meta http-equiv=
"Content-Type"
content=
"text/html; charset=gbk"
/>
<body>
11111111111
</body>
<script type=
"text/javascript"
src=
"jquery-1.4.2.min.js"
></script>
<script type=
"text/javascript"
>
jQuery.param=
function
( a ) {
var
s = [ ];
var
encode=
function
(str){
str = encodeURIComponent(str);
//str=escape(str);
//str=str.replace(/+/g,"%u002B");
return
str;
};
function
add( key, value ){
s[ s.length ] = encode(key) +
'='
+ encode(value);
};
// If an array was passed in, assume that it is an array
// of form elements
if
( jQuery.isArray(a) || a.jquery )
// Serialize the form elements
jQuery.each( a,
function
(){
add(
this
.name,
this
.value );
});
// Otherwise, assume that it's an object of key/value pairs
else
// Serialize the key/values
for
(
var
j
in
a )
// If the value is an array then the key names need to be repeated
if
( jQuery.isArray(a[j]) )
jQuery.each( a[j],
function
(){
add( j,
this
);
});
else
add( j, jQuery.isFunction(a[j]) ? a[j]() : a[j] );
$b =s.join(
"&"
).replace(/%20/g,
"+"
);
console.log($b);
// Return the resulting serialization
return
$b;
}
$.ajax({
url: 'test.php',
data:{
name:
"临风"
},
timeout: 20000,
//超时时间设定 data:para,//参数设置
success:
function
(html){
}
});
</script>
</html>
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
<?php
var_dump($_REQUEST);
echo $_REQUEST[
'name'
],
"
"
;
echo utf2gbk($_REQUEST[
'name'
]);
function
utf2gbk($data){
if
(is_array($data)){
return
array_map(
"utf2gbk"
,$data);
}
return
iconv(
"utf-8"
,
'gbk'
,$data);
}
function
gbk2utf8($data){
if
(is_array($data)){
return
array_map(
"utf2gbk"
,$data);
}
return
iconv(
"gbk"
,
'utf-8'
,$data);
}
?>
|
array(1) {
["name"]=>
string(12) "%u4E34%u98CE"
}
%u4E34%u98CE
%u4E34%u98CE