********************************************************************
* 著作權聲明
*
* 本文以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依然如此......