encodeURI/decodeURI與UrlEncode/UrlDecode,噩夢在繼續

來源:互聯網
上載者:User

 

********************************************************************
*                                                 著作權聲明
*
* 本文以Creative Commons的發布,請嚴格遵循該授權協議。
* 本文首發於部落格園, 此聲明為本文章中不可或缺的一部分。
* 作者網名:    浪子
* 作者EMAIL:dayichen (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依然如此......

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.