备注学院

LuLu

  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  5 随笔 :: 50 文章 :: 16 评论 :: 0 Trackbacks

[版权声明]:版权归作者所有,转载时请以超链接形式标明文章原始出处和作者信息及本声明:
http://www.open-lib.com/Forum/Read_69_1.action

前言:

当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中有这样的一段代码:

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的代码:

$.ajax({
 url: ajaxurl,
 type: 'POST',
 dataType: 'html',
 timeout: 
20000,//超时时间设定
 data:para,//参数设置
 success: function(html){

 }
});

通过上面代码可以知道,当设置了data时候,jquery内部会调用jQuery.param方法对参数encode(执行本应浏览器处理的encode)。

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代码:

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

posted on 2010-10-18 20:08 smildlzj 阅读(1811) 评论(3)  编辑  收藏

评论

# re: jQuery ajax在GBK编码下表单提交终极解决方案(非二次编码方法) 2010-10-18 22:04 heqs
不错的方法。。。  回复  更多评论
  

# re: jQuery ajax在GBK编码下表单提交终极解决方案(非二次编码方法) 2010-10-20 22:52 Unmi
好办法,改核心代码会有些麻烦,可否写个 jQuery 的插件来改变默认的行为。

关于 ajax,都是使用 utf8 字符集的,像 dwr, prototype 都是这样子的。

不过,我所参与的项目都是使用 utf-8 的字符集,可以避免这样的错误。  回复  更多评论
  

# re: jQuery ajax在GBK编码下表单提交终极解决方案(非二次编码方法) 2010-10-20 23:09 smildlzj
@Unmi
utf-8编码下当然不存在问题.
只是有的项目不是utf-8,例如163就不是了..

这个虽然是改变核心代码,但是只是在外部覆盖原有方法..

至于你说写成插件,其实也不是啥问题....等于是单独一套ajax,抛弃原有jq的..  回复  更多评论
  


只有注册用户登录后才能发表评论。


网站导航: