解码URIComponent与unescape,unescape有什么问题?

55

回答另一个问题时,我意识到我的Javascript/DOM知识已经有点过时了,因为我仍在使用escape/unescape来编码URL组件的内容,而现在似乎应该使用encodeURIComponent/decodeURIComponent

我想知道的是escape/unescape有什么问题?有一些模糊的建议说Unicode字符存在某种问题,但我找不到任何明确的解释。

我的网络经验相当片面,几乎全部是编写与Internet Explorer相关的大型Intranet应用程序。这涉及到大量使用escape/unescape,并且这些应用程序多年来已完全支持Unicode。

那么escape/unescape所谓的Unicode问题是什么?有没有人有任何测试用例来证明这些问题?


我认为这篇文章讲得很好。 - Peter Bailey
太好了,正是我想要的。我看问题在于Mozilla无法处理转义中的Unicode,这就解释了为什么我在使用仅限于IE的应用程序时没有遇到任何问题。 - andynormancx
我在过去的工作中只接触过IE浏览器内部应用程序,这既是一种幸运也是一种诅咒。幸运的是,我从未不得不应对IE / FF之间的差异,但同样的原因也让我倍感困扰。 - andynormancx
Mozilla和IE在Unicode方面都做了相同(好奇)的事情,即使文档没有提到。 - bobince
当使用(不)转义时,Chrome也在处理Unicode方面遇到了困难... - Jonathan Day
我知道你发帖时规则可能不同,但现在只提供链接的答案已经不被看好了,通常会被删除。然而,由于这个答案被删除会让你失去很多,所以我想给你一个机会通过编辑它来包含更多关于这个主题的信息(也许是链接另一侧内容的摘要)。谢谢。 - Mick MacCallum
4个回答

46
我想知道escape/unescape有什么问题? 它们本身并没有“错误”,只是一种特殊的字符串格式,看起来有点像URI参数编码,但实际上不是。特别地: - “+”表示加号而不是空格。 - 有一个特殊的“ %uNNNN”格式用于编码Unicode UTF-16代码点,而不是编码UTF-8字节。 因此,如果你使用escape()创建URI参数值,则对于包含加号或任何非ASCII字符的字符串,将会得到错误的结果。 escape()可以用作内部JavaScript编码方案,例如用于逃避cookie值。然而,现在所有浏览器都支持encodeURIComponent(最初并非如此),所以没有理由优先使用escape。 我所知道的仅有一种现代化的使用escape/unescape的方法,那就是利用URIComponent处理中的UTF-8处理,快速实现UTF-8编码器/解码器。
utf8bytes= unescape(encodeURIComponent(unicodecharacters));
unicodecharacters= decodeURIComponent(escape(utf8bytes));

一个很好的参考资料:http://unixpapa.com/js/querystring.html - 关于已弃用的escape/unescape、愚蠢的encodeURI/decodeURI和decodeURIComponent/encodeURIComponent - 怪癖及其使用方法。decodeURIComponent不会将“+”转换为空格。 - Curtis Yallop
转义符号可以转义单引号,而encodeURI则不行。这使得它对我的项目毫无用处。 - Matthew Oakley
bobince- 我目前正在使用这种方法来获取 utf8bytes= unescape(encodeURIComponent(unicodecharacters)); 当浏览器停止支持 unescape 方法后,我该如何实现相同的结果呢?谢谢。 - acabra85
1
@acabra85:最终会像 https://www.w3.org/TR/encoding/ 中的 TextEncoder/TextDecoder API 一样。目前还不支持,我也不会担心 escape/unescape 很快就会消失。 - bobince

11

escape仅对0到255范围内的字符进行操作(ISO-8859-1,即可以用单个字节表示的unicode代码点)。(*)

encodeURIComponent适用于javascript可以表示的所有字符串(即unicode基本多语言平面的全部范围,即unicode代码点0到1,114,111或0x10FFFF,覆盖了当前使用的几乎所有人类书写系统)。

这两个函数都产生url安全字符串,只使用0到127的代码点(US-ASCII),后者通过首先将字符串编码为UTF-8,然后应用从escape熟悉的%XX十六进制编码,对于任何不是url安全的代码点进行编码。

这恰好是为什么你可以在javascript中制作一个双函数调用的UTF-8编码器/解码器,而不需要任何循环或垃圾生成,通过组合这些基元来消除除UTF-8处理以外的所有副作用,就像unescapedecodeURIComponent版本在相反方向上做的那样。

(*) 脚注:一些现代浏览器,如谷歌Chrome已经被调整为在超出255个字符范围的情况下产生%uXXXX的转义字符,但是,与IETF标准化的基于UTF-8的编码相比,Web服务器对解码该编码的支持并不如此完善。


9

我遇到的另一个“现代”用途是解析可能包含无效UTF8字节序列的URI编码字符串。在某些情况下,decodeURIComponent可能会抛出异常。您可能需要捕获此异常并回退到使用unescape。

例如,'tür'编码为't%FCr',我曾看到Firefox生成这种编码(当字符被粘贴到地址栏后面的?中时)。


1
看起来那个漏洞在Firefox中已经被修复了。然而,有些人错误地使用ISO-8859-1而不是UTF-8对字符进行编码也是有可能的。 - Alexis Wilke

7

最好的答案是,在此网站上在线工作http://meyerweb.com/eric/tools/dencoder/

function decode() {
    var obj = document.getElementById('dencoder');
    var encoded = obj.value;
    obj.value = decodeURIComponent(encoded.replace(/\+/g,  " "));
}

这正是我所需要的,但对我来说非常重要的是要反转顺序。首先替换+符号,然后使用decodeURIComponent解码。在我的情况下,这很重要,因为我正在处理电子邮件地址。因此,电子邮件地址中的+符号被替换为空格是不正确的。电子邮件地址不允许空格,但允许加号符号。希望这能帮助其他人 :) - onassar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接