随笔-71  评论-634  文章-4  trackbacks-33

 

********************************************************************
*                                                 版权声明
*
* 本文以Creative Commons的知识共享署名-非商业性使用-相同方式共享发布,请严格遵循该授权协议。
* 本文首发于博客园, 此声明为本文章中不可或缺的一部分。
* 作者网名:    浪子
* 作者EMAILdayichen (at)163.com
* 作者BLOG:  Http://Www.Cnblogs.Com/Walkingboy
*
********************************************************************

encodeURI/decodeURI与UrlEncode/UrlDecode,噩梦在继续

-Written by 浪子@cnblogs.com  (07-04-11)

摘要:

关于encodeURI,标准似乎是这么定义的: 

"如果有空格就用%20代替,如果有其它字符就用%ASCII代替,如果有汉字等四个字节的字符,就用两个%ASCII来代替"

然而MS向来标新立异,继encodeURI之URL中文参数问题之后,encodeURI的噩梦继续袭来......

一、该死的空格

最近做两个页面的数据交换.由PageA发起Ajax请求到PageB,PageB从数据库读取数据返回给PageA,由于怕中间有特殊字符会导致js失败,所以使用了UrlEncode进行URI编码,再在客户端进行decodeURI解码.

结果发现空格无法被正确识别,UrlEncode将空格编码为+,而decodeURI只识别20%表示的空格。初步判断UrlEncode的编码格式和encodeURI不一致,为了验证这个看法,于是提取了键盘上的一些特殊符号进行编码比对:

 

字符:        ~    ! @    # $     % ^ & * ()_ +    - =
UrlEncode: %7e ! %40 %23 %24 %25 %5e %26 * ()_ %2b - %3d
encodeURI: ~    ! @    # $     %25 %5E & * ()_ +    - =
字符:        {    }    [    ] \ | ' ; :    "    / ? . , < >
UrlEncode: %7b %7d %5b %5d %5c %7c ' %3b %3a %22 %2f %3f . %2c %3c %3e
encodeURI: %7B %7D %5B %5D %5C %7C ' ; :    %22 / ? . , %3C %3E

 

这些比较可以看出,两个的编码确实存在比较大区别上,特别是对于特殊字符的处理上面.

由此相当,在encodeURI之URL中文参数问题中自己所认为了,asp.net对form的action进行了2次编码的判断应该是错的,其实并没有进行2次编码,只是asp.net在接受到encodeURI编码的action之后,利用UrlDecode进行解码,然后再次用UrlEncode进行编码写入Html中,由于编码格式不一致,所以Postback之后的URI,js就无法使用decodeURI进行正确解码.

由此可以知道,如果你用encodeURI编码的字符串,是可以通过UrlDecode解码出来的,也就是说UrlDecode可以识别encodeURI(js)和UrlEncode(c#)两个编码格式.可以想到,MS在设计这个类库的时候,已经考虑到了会接受到encodeURI的编码,按常理来想的话,既然考虑到了解码,自然会考虑到编码,也即UrlEncode应该提供可以编码成decodeURI可以解码的格式.可别的是,我一直无法找到这个方式.不知道是设计者给我们开的一个小玩笑,还是留下点瑕疵好让我们燃起编程的激情,不至于对千篇一律的Code工作感到厌倦,残念......

二、让SP来得更猛烈些吧

因为存在这个编码的不一致性,导致如果你的程序需要做比较多的Server-Client数据沟通的话,只能通过其他途径(json,xml等非URI),即使只是一个简单的字符串,你也需要增加许多额外的数据以满足你的格式.

一如MS的很多软件一样,SP满天飞,看来我也只好自己进行SP了.

 

分析下编码中差异,基本都集中在特殊字符的处理上,对于中文的处理貌似一致的(目前还没有测试出差异).于是定下了"利用encodeURI/decodeURI处理中文字符,其他的进行手工处理"的方案,修改了下之前的js代码:

 

KINN.Util.EncodeURI = function(unzipStr,isCusEncode){
    if(isCusEncode){
        var zipArray = new Array();
        var zipstr = "";
        var lens = new Array();
        for(var i=0;i<unzipStr.length;i++){
         var ac = unzipStr.charCodeAt(i);
         zipstr += ac;
         lens = lens.concat(ac.toString().length);
        }
        zipArray = zipArray.concat(zipstr);
        zipArray = zipArray.concat(lens.join("O"));
        return zipArray.join("N");
    }else{
        //return encodeURI(unzipStr);
        var zipstr="";
        var strSpecial="!\"#$%&'()*+,/:;<=>?[]^`{|}~%";
        var tt= "";
        for(var i=0;i<unzipStr.length;i++){
            var chr = unzipStr.charAt(i);
            var c=KINN.Util.StringToAscii(chr);
            tt += chr+":"+c+"n";
            if(parseInt("0x"+c) > 0x7f){
                 zipstr+=encodeURI(unzipStr.substr(i,1));
            }else{
                 if(chr==" ")
                    zipstr+="+";
                 else if(strSpecial.indexOf(chr)!=-1)
                    zipstr+="%"+c.toString(16);
                 else
                    zipstr+=chr;
                }
            }
        return zipstr;
    }
}
KINN.Util.DecodeURI = function(zipStr,isCusEncode){
    if(isCusEncode){
        var zipArray = zipStr.split("N");
        var zipSrcStr = zipArray[0];
        var zipLens;
        if(zipArray[1]){
            zipLens = zipArray[1].split("O");    
        }else{
            zipLens.length = 0;
        }
        
        var uzipStr = "";
        
        for(var j=0;j<zipLens.length;j++){
            var charLen = parseInt(zipLens[j]);
            uzipStr+= String.fromCharCode(zipSrcStr.substr(0,charLen));
            zipSrcStr = zipSrcStr.slice(charLen,zipSrcStr.length);
        }        
        return uzipStr;
    }else{
        //return decodeURI(zipStr);
        var uzipStr="";
        for(var i=0;i<zipStr.length;i++){
            var chr = zipStr.charAt(i);
            if(chr == "+"){
                 uzipStr+=" ";
            }else if(chr=="%"){
                 var asc = zipStr.substring(i+1,i+3);
                 if(parseInt("0x"+asc)>0x7f){
                     uzipStr+=decodeURI("%"+asc.toString()+zipStr.substring(i+3,i+9).toString()); ;
                     i+=8;
                 }else{
                     uzipStr+=KINN.Util.AsciiToString(parseInt("0x"+asc));
                     i+=2;
                 }
            }else{
                 uzipStr+= chr;
            }
        }
        return uzipStr;
    }
}
KINN.Util.StringToAscii = function(str){
    return str.charCodeAt(0).toString(16);
}
KINN.Util.AsciiToString = function(asccode){
    return String.fromCharCode(asccode);
}

 

 

三、浪子语:

很奇怪,为什么Asp.net老是存在某些小毛病小问题,不知道是设计者忽略了,还是真的为了改善我们程序员苦闷的编程生活?

java里面的编码就是和encodeURI一样的.

或许标准就是用来打破,IE如此,ASP.NET依然如此......

posted on 2007-04-11 13:24 浪子 阅读(5501) 评论(16)  编辑 收藏 网摘 所属分类: JavaScript/CSS

评论:
#1楼 2007-04-11 14:00 | lonkil[未注册用户]
Good!
  回复  引用    
#2楼 2007-04-11 14:19 | yyww      
貌似encodeURI/decodeURI是Javascript的标准,没有理由要求.NET使用Javascript的标准,有点区别很正常。
  回复  引用  查看    
#3楼 2007-04-11 14:22 | yzx110[未注册用户]
还没有遇到过这样的问题,
因为在js里只要有疑问的字符串统统用encodeURIComponent()来处理,然后发送到服务器端,到服务器端获取从来没出问题

  回复  引用    
#4楼 2007-04-11 14:32 | 袁永福[未注册用户]
encodeURI有问题可能和ASPX页面使用的编码格式相关,当ASPX采用默认的UTF8时可能存在字符编码问题,建议可以改用GB2312来试试。
  回复  引用    
#5楼 2007-04-11 14:41 | yunhuasheng      
不错,楼主真是细心之人.
  回复  引用  查看    
#6楼[楼主] 2007-04-11 14:42 | 浪子      
@yyww
或许是,但是开发中确实会存在问题,因为你需要双方沟通.
@yzx110
没错,服务端处理编码没有问题,反过来则行不通,而我刚好是需要反过来的那个人:-)
@袁永福
使用GB2313将会导致连锁反应,需要修改的将会更多,因为貌似大部分网站/组件等都是按UTF8设计的:)


  回复  引用  查看    
#7楼 2007-04-11 20:20 | Cat Chen      
encodeURIComponent呢?我见到多数人都是用这个的,而不是encodeURI。另外ASP.NET的做法是为了保持和ASP一致。
  回复  引用  查看    
#8楼 2007-04-11 21:07 | Clark Zheng      
偶就喜欢用encodeURIComponent,一个参数一个参数的编码,一般没什么问题,它的局限性在MSDN上有介绍
  回复  引用  查看    
#9楼 2007-04-11 23:23 | Ariel Y.      
偶最近也遇到了同样的问题,郁闷ing~~
  回复  引用  查看    
#10楼 2007-04-12 10:11 | 防范发[未注册用户]
是有这样的问题 以前反过来的时候 就直接把 + 替换成空格了 呵呵
楼主很仔细啊

  回复  引用    
#11楼 2007-04-13 08:08 | Wisdom-zh      
不错, 优先encodeURIComponent
  回复  引用  查看    
#12楼[楼主] 2007-04-25 08:39 | 浪子      
@Cat Chen
一样的,在encodeURI之URL中文参数问题中我已经尝试过了,Postback回来之后,照样无法用js端解码.

  回复  引用  查看    
#13楼 2007-04-28 21:49 | 怪怪[未注册用户]
.............,你服務器端用的UrlEncode,凴什麽要求客戶端一定能正確解碼,ASP.NET和IE/Firefox是兩個產品。首先是服務器端編碼問題必須排除,在這個問題上經常有細節被忽略;然後不行再重寫服務器端的Encoding方式,而不是在客戶端增加新的方法。
  回复  引用    
#14楼[楼主] 2007-04-29 08:47 | 浪子      
@怪怪
首先,作为开发人员,并不是你想怎么样就怎么样的。很多时候受限于需求。

 

其次,MS在UrlDecode上既然考虑到了两者的通讯问题,为什么只设计了C-S的情况,为什么忽略S-C的情况,这个只不过是举手之劳而已,当然谁也不能强制要求MS这样子,我们都还不够格。

 

再者,服务器编码问题已经进行测试,发现非此问题。重写服务端Encoding和重写客户端有啥区别?有什么好处和坏处?

 

 

thanks  


  回复  引用  查看    
#15楼 2007-11-04 21:28 | bingdian3721[未注册用户]
重写服务端Encoding不会像重写客户端一样增加通讯带宽啊
呵呵
重写客户端,你脚本增加了,通讯流量也就增加了,而且不是一点半点

  回复  引用    
#16楼[楼主] 2007-11-05 09:11 | 浪子      
此理由,在理^_^

--引用--------------------------------------------------
bingdian3721: 重写服务端Encoding不会像重写客户端一样增加通讯带宽啊
呵呵
重写客户端,你脚本增加了,通讯流量也就增加了,而且不是一点半点

--------------------------------------------------------

  回复  引用  查看    



发表评论

昵称: [登录] [注册]

主页:

邮箱:(仅博主可见)

评论内容:

  登录  注册

[使用Ctrl+Enter键快速提交评论]

0 708740




相关文章:

相关链接: