Answers:
EscapeDataString
始终使用(有关原因的更多信息,请参见下面的Livven回答)
编辑:删除死链接到两者如何在编码上有所不同
URLEncode
)。
我发现现有的答案并不令人满意,因此我决定更深入地解决该问题。令人惊讶的是,答案非常简单:
没有(几乎*)没有正当理由使用Uri.EscapeUriString
。如果您需要对字符串进行百分比编码,请始终使用Uri.EscapeDataString
。
*有关有效的用例,请参见最后一段。
为什么是这样?根据文档:
使用EscapeUriString方法准备一个未转义的URI字符串作为Uri构造函数的参数。
这真的没有道理。根据RFC 2396:
URI始终采用“转义”形式,因为对完整的URI进行转义或转义可能会更改其语义。
尽管引用的RFC已被RFC 3986取代,但这一点仍然存在。让我们通过查看一些具体示例进行验证:
您有一个简单的URI,如下所示:
http://example.org/
Uri.EscapeUriString
不会改变它。
您决定手动编辑查询字符串,而不考虑转义:
http://example.org/?key=two words
Uri.EscapeUriString
将(正确)为您腾出空间:
http://example.org/?key=two%20words
您决定进一步手动编辑查询字符串:
http://example.org/?parameter=father&son
但是,此字符串不会被更改Uri.EscapeUriString
,因为它假定与号表示另一个键值对的开始。这可能不是您想要的。
您实际上决定将key
参数设为father&son
,因此可以通过转义与号来手动修复先前的URL:
http://example.org/?parameter=father%26son
但是,Uri.EscapeUriString
也将转义百分比字符,从而导致双重编码:
http://example.org/?parameter=father%2526son
如您所见,使用 Uri.EscapeUriString
其用于预期目的将使其无法&
用作查询字符串中的键或值的一部分,而不能用作多个键值对之间的分隔符。
这是因为,为了使其适合转义完整URI,它会忽略保留字符,而仅转义既非保留也非保留的字符,这与文档相反。这样,您最终不会得到类似http%3A%2F%2Fexample.org%2F
,但是您确实遇到了上述问题。
最后,如果您的URI有效,则无需进行转义即可将其作为参数传递给Uri构造函数,如果无效,则调用 Uri.EscapeUriString
也不是一个神奇的解决方案。实际上,它在很多情况下(即使不是大多数情况下)都可以工作,但绝不是可靠的。
您应该始终通过收集键值对和百分比编码,然后将它们与必要的分隔符进行连接来构造URL和查询字符串。您可以Uri.EscapeDataString
为此目的而使用,但不能Uri.EscapeUriString
这样做,因为它不会转义保留字符,如上所述。
仅当您不能执行此操作时(例如,在处理用户提供的URI时),才可以将其Uri.EscapeUriString
用作最后的手段。但是前面提到的警告适用–如果用户提供的URI不明确,则结果可能不理想。
encodeURI
/ Uri.EscapeUriString
不需要经常为encodeURIComponent
/ Uri.EscapeDataString
(因为当你有必须在一个URI上下文中使用盲网址deaing),但是,这并不意味着它没有自己的位置。
加号(+)可以揭示这些方法之间的差异。在简单的URI中,加号字符表示“空格”。考虑向Google查询“快乐猫”:
这是一个有效的URI(请尝试),并且EscapeUriString
不会对其进行修改。
现在考虑向Google查询“ happy c ++”:
这是一个有效的URI(请尝试),但是它会搜索“ happy c”,因为两个加号被解释为空格。要解决此问题,我们可以将“ happy c ++”传递给EscapeDataString
和瞧*:
*)编码的数据字符串实际上是“ happy%20c%2B%2B”;%20是空格字符的十六进制,%2B是加号字符的十六进制。
如果您UriBuilder
按原样使用,则只需要EscapeDataString
适当地转义整个URI的某些组件即可。@Livven对这个问题的回答进一步证明,确实没有理由使用EscapeUriString
。
"https://www.google.com/?q=happy c++"
。看来我需要手动分割“?”,还是有更好的方法?
EscapeDataString
。如果您提供的URL是实际URL,则是,您只想分割为?
。
来源中的注释清楚地说明了差异。为什么不通过XML文档注释来提供此信息对我来说是一个谜。
EscapeUriString:
此方法将转义不是保留字符或保留字符的任何字符,包括百分号。请注意,EscapeUriString也不会转义“#”符号。
EscapeDataString:
此方法将转义不是保留字符的任何字符,包括百分号。
因此区别在于它们如何处理保留字符。EscapeDataString
逃脱他们;EscapeUriString
才不是。
根据RFC,保留字符为::/?#[]@!$&'()*+,;=
为了完整起见,未保留的字符为字母数字和 -._~
两种方法都转义既不保留也不保留的字符。
我不同意与一般观念认为EscapeUriString
是邪恶的。我认为只转义非法字符(例如空格)而不保留字符的方法很有用。但是它在处理%
角色方面确实有一个古怪之处。百分号编码的字符(%
后跟2个十六进制数字)在URI中是合法的。我认为EscapeUriString
,如果它检测到此模式并%
在立即以2个十六进制数字开头时避免编码,那将更加有用。
一个简单的例子
var data = "example.com/abc?DEF=あいう\x20えお";
Console.WriteLine(Uri.EscapeUriString(data));
Console.WriteLine(Uri.EscapeDataString(data));
Console.WriteLine(System.Net.WebUtility.UrlEncode(data));
Console.WriteLine(System.Web.HttpUtility.UrlEncode(data));
/*
=>
example.com/abc?DEF=%E3%81%82%E3%81%84%E3%81%86%20%E3%81%88%E3%81%8A
example.com%2Fabc%3FDEF%3D%E3%81%82%E3%81%84%E3%81%86%20%E3%81%88%E3%81%8A
example.com%2Fabc%3FDEF%3D%E3%81%82%E3%81%84%E3%81%86+%E3%81%88%E3%81%8A
example.com%2fabc%3fDEF%3d%e3%81%82%e3%81%84%e3%81%86+%e3%81%88%e3%81%8a
*/
Uri.EscapeDataString()
,如@Livven的答案中所述。使用其他方法,系统根本没有足够的信息来为每个可能的输入产生预期的结果。