如果只处理网址编码,我应该使用EscapeUriString?
答案 0 :(得分:177)
我没有找到满意的答案,所以我决定深入挖掘一下这个问题。令人惊讶的是,答案非常简单:
没有正当理由使用Uri.EscapeUriString
。如果您需要对字符串进行百分比编码,请始终使用Uri.EscapeDataString
。
这是为什么?根据{{3}}:
使用EscapeUriString方法准备一个未转义的URI字符串作为Uri构造函数的参数。
这并没有多大意义。根据{{3}}:
URI总是在"转义"表单,因为转义或取消转换已完成的URI可能会改变其语义。
虽然引用的RFC已被documentation废弃,但这一点仍然存在。让我们通过查看一些具体的例子来验证它:
你有一个简单的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
,因此您可以通过转义&符来手动修复以前的网址:
http://example.org/?parameter=father%26son
但是,Uri.EscapeUriString
也将转义百分比字符,从而导致双重编码:
http://example.org/?parameter=father%2526son
如您所见,将Uri.EscapeUriString
用于其预期目的使得无法将&
用作查询字符串中的键或值的一部分,而不是作为多个键值对之间的分隔符
这是因为,在错误的尝试使其适合转义完整的URI时,它忽略了保留字符,只转义既不保留也不保留的字符,BTW与RFC 2396相反。这样您就不会得到像http%3A%2F%2Fexample.org%2F
这样的内容,但最终会遇到上述问题。
最后,如果您的URI有效,则不需要将其转义为作为参数传递给Uri construtor,如果它无效,则调用Uri.EscapeUriString
isn&#39 ; ta魔术解决方案。实际上,它会在许多情况下发挥作用,如果不是大多数情况,但它绝不可靠。
您应该始终通过收集键值对和百分比编码构建URL和查询字符串,然后将它们与必要的分隔符连接起来。您可以将Uri.EscapeDataString
用于此目的,但不能Uri.EscapeUriString
,因为它不会转义保留字符,如上所述。
答案 1 :(得分:95)
始终使用EscapeDataString
(有关原因的详细信息,请参阅下面的Livven's answer)
编辑:删除了两者在编码方面的差异的死链接
答案 2 :(得分:54)
加号(+)字符可以揭示这些方法之间的差异。在简单的URI中,加号字符表示" space"。考虑向谷歌查询“快乐的猫”":
这是一个有效的URI(试一试),EscapeUriString
不会修改它。
现在考虑向Google查询"快乐的c ++":
这是一个有效的URI(试一试),但它产生了对#34; happy c"的搜索,因为这两个优点被解释为空格。为了解决这个问题,我们可以通过" happy c ++"到EscapeDataString
和voila * :
*)编码数据字符串实际上是#happy;%20c%2B%2B&#34 ;; %20是空格字符的十六进制,%2B是加号字符的十六进制。
如果您正在使用UriBuilder
,那么您只需要EscapeDataString
来正确转义整个URI的某些组件。 @ Livven对这个问题的回答进一步证明没有理由使用EscapeUriString
。
答案 3 :(得分:5)
source中的评论清楚地说明了这一区别。为什么这些信息不是通过XML文档注释提出的,这对我来说是一个谜。
<强> EscapeUriString:强>
此方法将转义任何非保留字符或 毫无保留的性格,包括百分号。注意 EscapeUriString也不会转义'#'符号。
<强> EscapeDataString:强>
此方法将转义任何非预留的字符 性格,包括百分号。
所以区别在于它们如何处理保留的字符。 EscapeDataString
逃脱了他们; EscapeUriString
没有。
根据RFC,保留字符为::/?#[]@!$&'()*+,;=
为完整起见,未保留的字符为字母数字和-._~
两种方法都转义既不保留也不保留的字符。
我不同意EscapeUriString
%
是邪恶的将军notion。我认为只有非法字符(如空格)而不是保留字符的方法才有用。但它在如何处理%
字符方面确实有一个怪癖。百分比编码的字符(EscapeUriString
后跟2个十六进制数字)在URI中是 legal 。我认为%
如果它检测到这种模式会更有用,并且当它立即以2个十六进制数字进行时避免编码element {
--main-bg-color: brown;
}
。
答案 4 :(得分: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
*/
答案 5 :(得分:0)
我使用加密字符串作为 URL 参数(例如 http://example.com/Test/myencryptedkey/param2/param3),因此没有任何 C# 加密方法可以提供安全的 url 参数。我最终使用了以下模式:
加密期间:
Uri.EscapeDataString(myencryptedkey).Replace('%', '~');
解密期间:
Uri.UnescapeDataString(myencryptedkey.Replace('~', '%'));
请注意,在加密期间,替换发生在 EscapeDataString() 之后,而在解密期间,替换发生在 UnescapeDataString() 之前;