什么时候应该使用转义而不是encodeURI / encodeURIComponent?


1392

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

使用转义:

escape("% +&=");

要么

使用encodeURI()/ encodeURIComponent()

encodeURI("http://www.google.com?var1=value1&var2=value2");

encodeURIComponent("var1=value1&var2=value2");

111
值得指出的是,encodeURIComponent("var1=value1&var2=value2")不是典型的用例。该示例将对=and 进行编码&,这可能不是预期的!encodeURIComponent通常单独应用于每个键值对中的值(每一对之后的部分=)。
蒂莫西·希尔兹

3
您需要对钥匙做任何事情吗?如果其中有=怎么办?(甚至有可能吗?)
马拉

3
@Mala一般而言,我还是Web编程的新手,但是我在有限的经验中使用过的方法是分别对键和值进行编码,以确保保留'=':var params = encodeURIComponent(key) + '=' + encodeURIComponent(value);-也许其他人知道更好的方法。
nedshares 2014年

1
@nedshares我正在使用它,但是据我所知,密钥似乎没有被编码……至少不是以相同的方式编码的。也许在键中有一个=违反规范?
马拉

1
还值得指出的是,最近的JavaScript实现提供了用于操纵URL及其查询字符串的高级接口URLURLSearchParams
巴特·罗宾逊

Answers:


1914

逃逸()

不要使用它! escape()B.2.1.2节中定义了转义,附件B引言中说:

...本附件中指定的所有语言功能和行为均具有一个或多个不良特征,在没有遗留用法的情况下,将从本规范中删除。……
在编写新的ECMAScript代码时,程序员不应使用或假定这些功能和行为的存在。

行为:

https://developer.mozilla.org/zh-CN/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 HEXDIG
sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
              / "*" / "+" / "," / ";" / "="

仅当百分号后接两个十六进制数字时才允许使用百分号,而百分号后接u不允许。

encodeURI()

需要有效的URL时,请使用encodeURI。拨打电话:

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

要得到:

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

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

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

encodeURIComponent()

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

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

请注意,encodeURIComponent不会转义该'字符。一个常见的错误是使用它来创建html属性,例如href='MyUrl',可能会遇到注入错误。如果要从字符串构造html,请使用"而不是使用'属性引号,或添加额外的编码层('可以编码为%27)。

有关此类型编码的更多信息,请检查:http : //en.wikipedia.org/wiki/Percent-encoding


31
@Francois,根据接收服务器的不同,它可能无法正确解码转义编码高位ASCII或非ASCII字符的方式,例如:ềểễếệ例如,如果bye转义编码,Python的FieldStorage类将无法正确解码上述字符串。

22
@Francois escape()编码除字母,数字和*@-_+./之外的低128个ASCII字符,而unescape()是escape()的反函数。据我所知,它们是为URL编码而设计的旧函数,仍然仅为实现向后兼容而实现。通常,除非与专门为其设计的应用程序/ Web服务/等进行交互,否则不应使用它们。
Anthony DiSanti 2011年

3
当然,除非您尝试将URL作为URI组件传递,否则请调用encodeURIComponent。
汤姆(Tom)2012年

4
为什么不处理单引号?
埃里克

11
@Eric它不对单引号进行编码,因为单引号是在URI(RFC-3986)中出现的完全有效的字符。当您在HTML中嵌入URI(单引号不是有效字符)时,就会出现问题。随之而来的是,在将URI 放入HTML文档之前,还应该对其进行“ HTML编码”(将替换'')。
李李

441

encodeURI()和之间的区别在于,encodeURIComponent()encodeURIComponent编码的是11个字符,而encodeURI编码的不是:

该表包含encodeURI和encodeURIComponent的十个区别

我使用以下代码通过Google Chrome中的console.table轻松生成了该表:

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);


这个浏览器不依赖吗?
Pacerier 2014年

4
@bladnman encodeURI和encodeURIComponent在所有主流浏览器中都应以这种方式工作。您可以在Chrome和Firefox中测试以上代码,因为它们都支持console.table。在其他浏览器(包括Firefox和Chrome)中,您可以使用以下代码:var arr=[]; for(var i=0;i<256;i++){var char=String.fromCharCode(i); if(encodeURI(char)!==encodeURIComponent(char)) console.log("character: "+char + " | encodeURI: " +encodeURI(char) + " |encodeURIComponent: " + encodeURIComponent(char) ) }
Johann Echavarria 2014年

1
我的意思是@Pacerier :)
Johann Echavarria 2014年

@Pacerier应该在不同的浏览器相同的,除非原来的规范是太暧昧了...还看到stackoverflow.com/questions/4407599/...
克里斯托夫•鲁西

2
我需要多次支持!不幸的是只能投票一次。
Ramazan Polat

46

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

我在尝试理解以下原因时发现了它,为什么为什么解码URIComponent无法正确解码“ +”。这是摘录:

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!

11
您链接到的文章包含很多废话。在我看来,作者本人并不理解该功能适用​​于什么……
Christoph

2
@Christoph在我看来,这一切都很合理。特别是,我同意他的观点,即encodeURI似乎仅在相当模糊的边缘情况下才有用,并且确实不需要存在。我和他有一些意见分歧,但是我看不到那里有任何完全错误或愚蠢的事情。你到底在说什么废话?
Mark Amery 2013年

1
元素的enctype属性FORM指定用于编码表单数据集以提交给服务器的内容类型。 application / x-www-form-urlencoded 这是默认的内容类型。用这种内容类型提交的表单必须按以下方式编码:[...] 空格字符用“ +”代替,[...]非字母数字字符用“%HH”代替,[...] 参考:HTML4 Sepc
cychoi

2
encodeURIComponent('A + B')。replace(/ \%20 / g,'+')+'\ n'+ encodeURIComponent(“ A +%2B + B” .replace(/ \ + / g,'%20' ));
Zlatin Zlatev 2015年

39

encodeURIComponent无法编码-_.!~*'(),从而导致将数据以xml字符串发布到php时出现问题。

例如:
<xml><text x="100" y="150" value="It's a value with single quote" /> </xml>

一般逃脱 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 "";
}

5
它还不执行#(磅/哈希/数字)符号,即%23。
xr280xr 2014年

1
@ xr280xr是什么意思?encodeURIComponent会将#编码为%23(也许不是在2014年吗?)
DavidBalažic18年

38

encodeURI()-escape()函数用于javascript转义,而不是HTTP。


如果我有这样的网址:var url = "http://kuler-api.adobe.com/rss/get.cfm?startIndex=0&itemsPerPage=20&timeSpan=0&listType=rating"...并且我想通过Google Ajax API访问它,例如:var gurl = "http://ajax.googleapis.com/ajax/services/feed/load?v=1.0&callback=?&q=" + url;...然后我必须使用escape(url)encodeURI(url)似乎无法使用类似的参数。
兰斯·波拉德

15
您应使用ecnodeURIComponent(url)
Ustaman Sangat'5

2
这三个功能都有其问题。最好创建自己的函数来完成任务。
杰里·约瑟夫

17

小型对照表Java,JavaScript,PHP。

1. Java URLEncoder.encode (using UTF8 charset)
2. JavaScript encodeURIComponent
3. JavaScript escape
4. PHP urlencode
5. 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

12

我建议不要按原样使用这些方法之一。编写自己的函数,做正确的事。

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 it
        replace(/['()]/g, escape). // i.e., %27 %28 %29
        replace(/\*/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/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent


1
这是一个很好的答案(如果它在chrome边缘和Firefox中兼容,而又没有犯任何错误)
yan bellavance

10

还要记住,它们都编码不同的字符集,并适当选择所需的字符集。encodeURI()编码的字符数少于encodeURIComponent()的编码字符数,而encodeURIComponent()的编码字符数少于(也不同于丹尼普的观点)编码的字符比escape()少。


8

为了进行编码,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'); 将给出-http%3A%2F%2Fstackoverflow.com

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

encodeURIComponent与encodeURI的不同之处在于,它对保留字符和encodeURI的数字符号#进行编码


3

我发现即使对各种方法的各种用途和功能都有很好的了解,对各种方法进行实验也是一个很好的检查方法。

为此,我找到了这个网站对于确认我怀疑自己在做适当的事情非常有用。事实证明,它对于解码encodeURIComponent的字符串很有用,这可能很难解释。一个很棒的书签:

http://www.the-art-of-web.com/javascript/escape/


2

接受的答案是好的。要扩展最后一部分:

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

为了安全起见,请百分比编码未保留的字符应对进行编码。

您可以使用此方法将其转义(来源Mozilla

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

// fixedEncodeURIComponent("'") --> "%27"

2

@ 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.logconsole.table(用于更漂亮的输出)。


2

约翰的桌子启发,我决定延长桌子。我想查看对哪些ASCII字符进行了编码。

console.table的屏幕截图

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


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

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>

1

我有这个功能...

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;
};

4
@ChristianVielma转义()已弃用,但从未引用w3schools.com。参见w3fools.com
Jerry Joseph

4
@Christian Vielma -一些人找到的参考材料W3Schools的较少争议的和有用的。并非所有人都同意不应引用W3Schools。
DavidRR 2014年

2
W3Schools确实受到了不良说唱。当然,它们并不总是准确的,但是我又遇到了很多博客文章,这些文章也完全是错误的。对我来说,有时只是学习一些术语,然后再深入学习其他资源,这是一个很好的起点。最重要的是,当涉及到这类资源时,单一资源永远都不会成为圣经。
ryandlf 2015年

似乎@molokoloco将此功能写为encodeURI对不存在但escape存在的版本的后备。
SOFe
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.