encodeURI/decodeURI与UrlEncode/UrlDecode,噩梦在继续
********************************************************************
* 版权声明
*
* 本文以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依然如此......
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· SQL Server 2025 AI相关能力初探
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库