什么时候应该使用转义而不是编码URI/编码URIComponent?

当编码要发送到Web服务器的查询字符串时-何时使用escape()以及何时使用encodeURI()encodeURIComponent()

使用转义:

escape("% +&=");

使用codeURI()/codeURIComponent()

encodeURI("http://www.google.com?var1=value1&var2=value2");
encodeURIComponent("var1=value1&var2=value2");
553083 次浏览

eccodeURI()——逸出()函数用于javascript转义,而不是HTTP。

还要记住,它们都对不同的字符集进行编码,并适当地选择您需要的字符集。

逃逸()

不要用它!escape()B.2.1.2逃逸节中定义,附件B的导言案文表示:

…本附件中指定的所有语言特性和行为都有一个或多个不良特征,如果没有遗留用法,将从本规范中删除。…
程序员在编写新的ECMAScript代码时不应该使用或假设这些特性和行为的存在。

行为规范:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/escape

特殊字符编码:@*_+-。/

代码单元值为0xFF或更小的字符的十六进制形式是两位数的转义序列:%xx

对于具有更大代码单元的字符,使用四位数格式%uxxxx。这在查询字符串中是不允许的(如RFC3986中定义的):

query       = *( pchar / "/" / "?" )pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"pct-encoded   = "%" HEXDIG HEXDIGsub-delims    = "!" / "$" / "&" / "'" / "(" / ")"/ "*" / "+" / "," / ";" / "="

百分号只允许直接跟在两个六位数后面,不允许百分比跟在u后面。

codeURI()

当您想要一个有效的URL时,请使用编码URI。进行以下调用:

encodeURI("http://www.example.org/a file with spaces.html")

以获得:

http://www.example.org/a%20file%20with%20spaces.html

不要调用eccodeURIComponent,因为它会破坏URL并返回

http%3A%2F%2Fwww.example.org%2Fa%20file%20with%20spaces.html

需要注意的是,和codeURIComponent一样,codeURI不会转义'字符。

EncodeURIComponent()//代码类型

当您想对URL参数的值进行编码时,请使用编码URIComponent。

var p1 = encodeURIComponent("http://example.org/?a=12&b=55")

然后您可以创建您需要的URL:

var url = "http://example.net/?param1=" + p1 + "&param2=99";

您将获得完整的URL:

http://example.net/?param1=http%3A%2F%2Fexample.org%2F%Ffa%3D12%26b%3D55&param2=99

请注意,codeURIComponent不会转义'字符。一个常见的bug是使用它来创建HTML属性,例如href='MyUrl',这可能会遭受注入bug。如果您要从字符串构建html,请使用"而不是'作为属性引号,或者添加额外的编码层('可以编码为%27)。

有关此类编码的更多信息,您可以查看:http://en.wikipedia.org/wiki/Percent-encoding

我发现这篇文章很有启发性:Javascript疯狂:查询字符串解析

当我试图理解为什么decdeURIComponent不能正确解码'+'时,我发现了它。这是一个摘录:

String:                         "A + B"Expected Query String Encoding: "A+%2B+B"escape("A + B") =               "A%20+%20B"     Wrong!encodeURI("A + B") =            "A%20+%20B"     Wrong!encodeURIComponent("A + B") =   "A%20%2B%20B"   Acceptable, but strange
Encoded String:                 "A+%2B+B"Expected Decoding:              "A + B"unescape("A+%2B+B") =           "A+++B"       Wrong!decodeURI("A+%2B+B") =          "A+++B"       Wrong!decodeURIComponent("A+%2B+B") = "A+++B"       Wrong!

codeURIComponent不编码-_.!~*'(),导致在xml字符串中将数据发布到php时出现问题。

例如:

使用encodeURI
的常规转义%3Cxml%3E%3Ctext%20x=%22100%22%20y=%22150%22%20value=%22It's%20a%20value%20with%20single%20quote%22%20/%3E%20%3C/xml%3E

您可以看到,单引号没有编码。为了解决问题,我创建了两个函数来解决我项目中的问题,用于编码URL:

function encodeData(s:String):String{return encodeURIComponent(s).replace(/\-/g, "%2D").replace(/\_/g, "%5F").replace(/\./g, "%2E").replace(/\!/g, "%21").replace(/\~/g, "%7E").replace(/\*/g, "%2A").replace(/\'/g, "%27").replace(/\(/g, "%28").replace(/\)/g, "%29");}

解码URL:

function decodeData(s:String):String{try{return decodeURIComponent(s.replace(/\%2D/g, "-").replace(/\%5F/g, "_").replace(/\%2E/g, ".").replace(/\%21/g, "!").replace(/\%7E/g, "~").replace(/\%2A/g, "*").replace(/\%27/g, "'").replace(/\%28/g, "(").replace(/\%29/g, ")"));}catch (e:Error) {}return "";}

我有这个功能…

var escapeURIparam = function(url) {if (encodeURIComponent) url = encodeURIComponent(url);else if (encodeURI) url = encodeURI(url);else url = escape(url);url = url.replace(/\+/g, '%2B'); // Force the replacement of "+"return url;};

我发现,即使在很好地掌握了它们的各种用途和功能之后,尝试各种方法也是一个很好的理智检查。

为此,我发现本网站非常有用,可以证实我的怀疑,即我正在做一些适当的事情。它也被证明对解码编码URIComponent'ed字符串很有用,这可能相当难以解释。一个很棒的书签:

我建议不要像现在这样使用这些方法之一。编写自己的函数来做正确的事情。

MDN给出了一个很好的url编码示例,如下所示。

var fileName = 'my file(2).txt';var header = "Content-Disposition: attachment; filename*=UTF-8''" + encodeRFC5987ValueChars(fileName);
console.log(header);// logs "Content-Disposition: attachment; filename*=UTF-8''my%20file%282%29.txt"

function encodeRFC5987ValueChars (str) {return encodeURIComponent(str).// Note that although RFC3986 reserves "!", RFC5987 does not,// so we do not need to escape itreplace(/['()]/g, escape). // i.e., %27 %28 %29replace(/\*/g, '%2A').// The following are not required for percent-encoding per RFC5987,//  so we can allow for a little better readability over the wire: |`^replace(/%(?:7C|60|5E)/g, unescape);}

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent

encodeURI()encodeURIComponent()之间的区别正好是11个字符由编码URIComponent编码,但不是由编码URI编码:

表与10之间的差异编码URI和编码URIComponent

我在Google中使用console.table轻松生成了这个表Chrome使用以下代码:

var arr = [];for(var i=0;i<256;i++) {var char=String.fromCharCode(i);if(encodeURI(char)!==encodeURIComponent(char)) {arr.push({character:char,encodeURI:encodeURI(char),encodeURIComponent:encodeURIComponent(char)});}}console.table(arr);

小对照表Javavs. JavaScript vs. PHP。

1. Java URLEncoder.encode (using UTF8 charset)2. JavaScript encodeURIComponent3. JavaScript escape4. PHP urlencode5. PHP rawurlencode
char   JAVA JavaScript --PHP---[ ]     +    %20  %20  +    %20[!]     %21  !    %21  %21  %21[*]     *    *    *    %2A  %2A[']     %27  '    %27  %27  %27[(]     %28  (    %28  %28  %28[)]     %29  )    %29  %29  %29[;]     %3B  %3B  %3B  %3B  %3B[:]     %3A  %3A  %3A  %3A  %3A[@]     %40  %40  @    %40  %40[&]     %26  %26  %26  %26  %26[=]     %3D  %3D  %3D  %3D  %3D[+]     %2B  %2B  +    %2B  %2B[$]     %24  %24  %24  %24  %24[,]     %2C  %2C  %2C  %2C  %2C[/]     %2F  %2F  /    %2F  %2F[?]     %3F  %3F  %3F  %3F  %3F[#]     %23  %23  %23  %23  %23[[]     %5B  %5B  %5B  %5B  %5B[]]     %5D  %5D  %5D  %5D  %5D----------------------------------------[~]     %7E  ~    %7E  %7E  ~[-]     -    -    -    -    -[_]     _    _    _    _    _[%]     %25  %25  %25  %25  %25[\]     %5C  %5C  %5C  %5C  %5C----------------------------------------char  -JAVA-  --JavaScript--  -----PHP------[ä]   %C3%A4  %C3%A4  %E4     %C3%A4  %C3%A4[ф]   %D1%84  %D1%84  %u0444  %D1%84  %D1%84

为了编码的目的,JavaScript给出了三个内置函数——

  1. escape()-不编码@*/+此方法在ECMA 3之后已弃用,因此应避免使用。

  2. encodeURI()-不编码~!@#$&*()=:/,;?+'它假定URI是一个完整的URI,因此不会对URI中具有特殊含义的保留字符进行编码。当目的是转换完整的URL而不是URL的某些特殊段时,使用此方法。示例-encodeURI('http://stackoverflow.com');将给出-http://stackoverflow.com

  3. encodeURIComponent()-不编码- _ . ! ~ * ' ( )此函数通过将某些字符的每个实例替换为表示字符UTF-8编码的一个、两个、三个或四个转义序列来编码统一资源标识符(URI)组件。此方法应用于转换URL的组件。例如,需要附加一些用户输入示例-encodeURIComponent('http://stackoverflow.com');将给出-超文本传输协议%3A%2F%2Fstackoverflow.com

所有这些编码都以UTF 8执行,即字符将以UTF-8格式转换。

编码器URI组件与编码器URI的不同之处在于它编码保留字符和编码器URI的数字符号#

答案是肯定的。扩展到最后一部分:

请注意,codeURIComponent不会转义'字符。一个常见的bug是使用它来创建html属性,例如href='MyUrl'可能会遭受注射bug。如果您正在构建html从字符串,要么使用“而不是”作为属性引号,要么添加一个额外的编码层('可以编码为%27)。

如果你想安全起见,百分比编码非保留字符也应该被编码。

您可以使用此方法来转义它们(来源Mozilla

function fixedEncodeURIComponent(str) {return encodeURIComponent(str).replace(/[!'()*]/g, function(c) {return '%' + c.charCodeAt(0).toString(16);});}
// fixedEncodeURIComponent("'") --> "%27"

现代重写@johann-echavarria的回答:

console.log(Array(256).fill().map((ignore, i) => String.fromCharCode(i)).filter((char) =>encodeURI(char) !== encodeURIComponent(char)? {character: char,encodeURI: encodeURI(char),encodeURIComponent: encodeURIComponent(char)}: false))

或者,如果您可以使用表,请将console.log替换为console.table(对于更漂亮的输出)。

Johann的桌子的启发,我决定扩展表。我想看看哪些ASCII字符被编码。

console.table截图

var ascii = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~";
var encoded = [];
ascii.split("").forEach(function (char) {var obj = { char };if (char != encodeURI(char))obj.encodeURI = encodeURI(char);if (char != encodeURIComponent(char))obj.encodeURIComponent = encodeURIComponent(char);if (obj.encodeURI || obj.encodeURIComponent)encoded.push(obj);});
console.table(encoded);

表格仅显示编码字符。空单元格表示原始字符和编码字符相同。


只是为了额外,我添加了另一个表#0 vs#1。唯一的区别似乎是空格字符的编码。

console.table截图

<script><?php$ascii = str_split(" !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~", 1);$encoded = [];foreach ($ascii as $char) {$obj = ["char" => $char];if ($char != urlencode($char))$obj["urlencode"] = urlencode($char);if ($char != rawurlencode($char))$obj["rawurlencode"] = rawurlencode($char);if (isset($obj["rawurlencode"]) || isset($obj["rawurlencode"]))$encoded[] = $obj;}echo "var encoded = " . json_encode($encoded) . ";";?>console.table(encoded);</script>

自己试试encodeURI()encodeURIComponent()

console.log(encodeURIComponent('@#$%^&*'));

Input: @#$%^&*. Output: %40%23%24%25%5E%26*. So, wait, what happened to *? Why wasn't this converted? It could definitely cause problems if you tried to do linux command "$string". TLDR: You actually want fixedEncodeURIComponent() and fixedEncodeURI(). Long-story...

When to use encodeURI()? Never. encodeURI() fails to adhere to RFC3986 with regard to bracket-encoding. Use fixedEncodeURI(), as defined and further explained at the MDN encodeURI() Documentation...

function fixedEncodeURI(str) {return encodeURI(str).replace(/%5B/g, '[').replace(/%5D/g, ']');}

什么时候使用#0?从不。encodeURIComponent()在编码方面未能遵守RFC3986:!'()*。使用fixedEncodeURIComponent(),如MDN编码URIComponent()文档中定义和进一步解释的那样…

function fixedEncodeURIComponent(str) {return encodeURIComponent(str).replace(/[!'()*]/g, function(c) {return '%' + c.charCodeAt(0).toString(16);});}

然后,您可以使用fixedEncodeURI()来编码单个URL片段,而fixedEncodeURIComponent()将编码URL片段和连接器;或者,简单地说,fixedEncodeURI()不会编码+@?=:#;,$&(因为&+是常见的URL运算符),但fixedEncodeURIComponent()会。