jQuery ajax在GBK编码下表单提交终极解决方案(非二次编码方法)

 

前言:

当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与作者交流。

sushi0k
#2楼
发表于:2011-01-28 18:02:06

作者你好,看到你的文章讲解的很详细,让初学者和第一次遇到这种问题的人都能够大致了解问题所在。

我的问题是,我在jsp页面贴上了你的jQuery.param函数。然后我在servlet获取参数的时候出现了报错:
System.out.println(request.getParameter("vals"));//执行这句的时候,出现了如下错误。
java.io.CharConversionException: isHexDigit

按楼主的文章所述,似乎没有提到servlet需要进行一些处理。还是楼主遗漏了。
还请楼主提示一些,偶还没懂。我的email是759063617@qq.com

QQ:759063617  感谢楼主的文章。

路路
#3楼
发表于:2011-01-28 18:51:18
回复: sushi0k

不需要什么后续处理的噢....

平时怎么接收.....还是那样接收...

按照你的说法...你还没解决接收中文问题......tomcat的吗?

wanglei_licnancan
#4楼
发表于:2011-04-06 15:16:39

楼主您好!

我已经将jQuery.param函数贴在jsp页面中,但是后台取到的中文仍是乱码,是weblogic环境,由于项目编码所限,页面以及sevlet均是GBK编码,请问,除了将param方法贴在JSP页面中,还需要做什么嘛?

我的QQ:88358148,望楼主指教~ 感激不尽!

谢谢!

lulu
#5楼
发表于:2011-04-06 20:05:30
回复: wanglei_licnancan

你可以用firebug看看加log或者alert看看,看是否有执行上面的代码。

一般,如果起作用,接受参数的jsp或者setvlet都没问题的。

showicy
#6楼
发表于:2011-05-14 13:08:10

不太理解:

用escape对中文进行的是unicode编码。

而服务端用gbk进行解码。

 

编码跟解码字符集不对,这样不会乱码吗???

lulu
#7楼
发表于:2011-05-15 18:05:17
回复: showicy

unicode跟字符集没关系吧,所有东西都可以以unicode表示

rain85922
#8楼
发表于:2011-08-22 10:44:22

楼主你好,用你这个重写jquery的代码 这一行在IE8下报错了

str=str.replace(/+/g,"%u002B");

说+  是“错误的数量词”

别的字符好像就可以  如-

另:我将str=str.replace(/+/g,"%u002B");改为str=str.replace(/+/g,"%u002B");

在页面上加上该段代码后,页面提交form,整个bean中包含中文的属性在后台都变为null了

lulu
#9楼
发表于:2011-08-22 16:08:26
回复: rain85922

改成这样试试:

str=str.replace(/\+/g,"%u002B");

lcffufly
#10楼
发表于:2011-09-09 16:03:10

测试失败,请楼主指导一下:万分感谢!

?
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>
lcffufly
#11楼
发表于:2011-09-09 16:03:55
?
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
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值