我应该使用encodeURI还是encodeURIComponent来编码URL?

431

这两种方法中哪一种应该用于编码URL?


7
也请参阅https://dev59.com/OXVD5IYBdhLWcg3wI3-L#3608791。 - Pacerier
30
一个主要的区别是encodeURI不会对斜杠/进行编码,因此:encodeURIComponent("ac/dc") => ac%2FdcencodeURI("ac/dc") => ac/dc - user993683
这可能会有所帮助:"encodeURIComponent()和encodeURI()通过使用它们的UTF-8编码替换URL保留字符来对URI进行编码....它们之间的区别在于encodeURI不会对queryString或hash值进行编码...URL不允许许多特殊字符,比如空格或斜杠。然而,这些特殊字符是生活的一部分,因此URL编码被发明出来了。" 来源 - user1063287
请参见特定部分标题为“encodeURIComponent与encodeURI的区别如下”:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent#Description - user1063287
9个回答

470

这取决于你实际想要做什么。

encodeURI 假设输入是一个完整的 URI,其中可能包含一些需要编码的字符。

encodeURIComponent将对所有具有特殊含义的内容进行编码,因此您可以将其用于 URI 的组件,例如

var world = "A string with symbols & characters that have special meaning?";
var uri = 'http://example.com/foo?hello=' + encodeURIComponent(world);

178

如果你要编码一个字符串并将其放入URL组件(查询字符串参数)中,应该调用 encodeURIComponent

如果你要对现有的URL进行编码,请使用encodeURI


2
如果我正在使用Ajax,如何解码传递给PHP的URL? - Aditya Shukla
9
不需要你来做,网络服务器会自动完成这个任务。 - Quentin
@Aditya:这取决于你在做什么。 - SLaks
3
好的。当我说 webserver 会处理时,可能有些草率,但无论你使用哪个库来读取表单数据,它都会为你处理这个问题。 - Quentin
@SLaks,你说的关于%20代表空格是正确的。那个评论应该被删除了。我错误地诊断了一个问题,导致我头晕目眩并发表了那个评论。现在已经删除了(希望如此)。 - Michael Khalili
显示剩余5条评论

61

xkr.us有一个很好的讨论,并附有示例。引用他们的总结:

escape()方法不会对+字符进行编码,而该字符被解释为空格,在服务器端和表单填写的带有空格字段时生成。 由于这个缺点以及这个函数不能正确处理非ASCII字符,所以应尽可能避免使用escape()。 最好的替代方案通常是encodeURIComponent()。

escape()不会对@*/+进行编码

与escape()相比,使用encodeURI()方法更加专业化,因为它对URI进行编码,而不是查询字符串,后者是URL的一部分。 当您需要编码一个字符串以用于任何需要保留某些字符未编码的URI资源时,请使用此方法。 请注意,此方法不会对 '字符进行编码,因为它是URI中的有效字符。

encodeURI()不会对~!@#$&*()=:/,;?+进行编码

最后,在大多数情况下,应使用encodeURIComponent()方法对URI的单个组件进行编码。 此方法将对在URI中通常被识别为特殊字符的某些字符进行编码,以便包括许多组件。 请注意,此方法不会对 '字符进行编码,因为它是URI中的有效字符。

encodeURIComponent()不会对~!*()'进行编码


最近学到,TOMCAT 9服务器对于您可以发送到URL的内容更加挑剔。在需要编码的内容中存在“空格”时,encodeURIComponent()似乎效果更好。Tomcat 8不在意,但是9要求更高。 - Aggie Jon of 87
1
换句话说,如果您尝试将带有“#”的文件名转换为URL,则encodeURI会失败。 - gman

59

这里是总结。

  1. escape() 不会对 @ * _ + - . / 进行编码,不要使用它。

  2. encodeURI() 不会对 A-Z a-z 0-9 ; , / ? : @ & = + $ - _ . ! ~ * ' ( ) # 进行编码。当你的输入是完整的 URL(例如'https://searchexample.com/search?q=wiki')时,请使用它。

  3. encodeURIComponent() 不会对 A-Z a-z 0-9 - _ . ! ~ * ' ( ) 进行编码。当你的输入是完整 URL 的一部分时,请使用它。例如:const queryStr = encodeURIComponent(someString)


3
这是一个很好的答案,因为它准确地说明了它们的作用。然而,我仍然有一个问题,关于我应该在什么情况下使用哪个。如果我的URI组件是完整的URL,那我应该使用上述规则2还是规则3?或者像encodeURIComponent(encodeURI(theCompleteURI))一样同时使用两者? - Panu Logic
1
如果您想将完整的URL放入查询参数中,请使用encodeURIComponent,例如: https://example.test/?url=https%3A%2F%2Fexample.test%2fhome - Paul Watson
如果我使用encodeURIComponent来编码完整的URL会发生什么?那会破坏什么吗?何时需要使用encodeURI()并且绝不能使用encodeURIComponent()? - marcg

45

encodeURIencodeURIComponent 有不同的用途。
一些不同点如下:

  1. encodeURI 用于编码整个URL,而encodeURIComponent 用于编码URI中的组件,例如查询字符串。

  2. 11个字符不被encodeURI编码,但被encodeURIComponent编码。清单如下:

字符 encodeURI encodeURIComponent
# # %23
$ $ %24
& & %26
+ + %2B
, , %2C
/ / %2F
: : %3A
; ; %3B
= = %3D
? ? %3F
@ @ %40

注意:
encodeURIComponent 不会编码-_.!~*'(),如果想要这些字符被编码,必须将它们替换为相应的UTF-8字符序列。

如果您想了解encodeURI和encodeURIComponent更多的信息,请查看参考链接。参考链接

12

encodeURIComponent() :假设其参数是URI的某一部分(例如协议、主机名、路径或查询字符串)。因此,它会转义用于分隔URI部分的标点符号字符。

encodeURI():用于编码现有URL。


12

encodeURIencodeURIComponent的区别:

encodeURIComponent(value)主要用于编码查询字符串参数值,并对value中的每个适用字符进行编码。而encodeURI则忽略协议前缀(http://)和域名。


在非常罕见的情况下,如果您想要实现手动编码以编码附加字符(尽管它们在典型情况下不需要被编码),比如:! *,那么您可能会使用:

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

(来源)


6
在 URL 中,不应该对这些字符进行转义。 - Arashsoft
正如引用的文档所说:“这些字符没有正式的URI分隔用途”。 - caesarsol
@caesarsol 所以,我应该编辑我的答案吗?请让我知道您的想法,因为我无法理解引用文档的含义。 - T.Todua
除非您正在执行正常的URL编码用例之外的操作,否则对这些字符进行编码就毫无意义 :) - caesarsol
很好的回答,已点赞!我不确定为什么有人说编码“*”是无用的;如果有人认为编码*是无用的,请随意在您的主目录上运行rm * - HoldOffHunger

5

其他答案已经描述了其目的。以下是每个功能实际转换的字符:

control = '\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F'
        + '\x10\x11\x12\x13\x14\X15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F'
                                                                    + '\x7F'
encodeURI         (control + ' "%<>[\\]^`{|}'                             )
encodeURIComponent(control + ' "%<>[\\]^`{|}' + '#$&,:;=?' + '+/@'        )
escape            (control + ' "%<>[\\]^`{|}' + '#$&,:;=?' +       "!'()~")

以上所有字符都被转换为百分号十六进制代码。空格变成%20,百分号变成%25等等。以下字符不会被转换。

以下是函数不会转换的字符:

pass_thru = '*-._0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'

encodeURI         (pass_thru + '#$&,:;=?' + '+/@' + "!'()~")
encodeURIComponent(pass_thru +                      "!'()~")
escape            (pass_thru +              '+/@'          )

-1
通常情况下,请使用encodeURIComponent。不要因为名称长而害怕它的使用,对我来说,这是更常用的方法。同时,不要被诱惑使用encodeURI,因为你测试它并且它似乎可以正确编码,但它可能不是你想要使用的,即使在名字字段中使用“Fred”进行简单测试成功,但当你使用更高级的文本,如添加一个&符号或一个井号时,它将失败。你可以查看其他答案了解原因。

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