EscapeUriString 和 EscapeDataString 有啥区别?
Posted
技术标签:
【中文标题】EscapeUriString 和 EscapeDataString 有啥区别?【英文标题】:What's the difference between EscapeUriString and EscapeDataString?EscapeUriString 和 EscapeDataString 有什么区别? 【发布时间】:2011-05-22 17:57:38 【问题描述】:如果只处理url编码,我应该使用EscapeUriString?
【问题讨论】:
始终使用Uri.EscapeDataString()
转义每个单独的值,如@Livven 的回答中所述。使用其他方法时,系统根本没有足够的信息来为每个可能的输入产生预期的结果。
【参考方案1】:
始终使用EscapeDataString
(有关原因的更多信息,请参阅下面的Livven's answer)
编辑:删除了两者在编码上有何不同的死链接
【讨论】:
我不确定该链接是否提供了更多信息,因为它是关于取消转义而不是转义。 基本是一样的区别。如果你真的阅读了这篇文章,中间有一个表格,它实际上转义(不是 unescapes)以显示差异(也与URLEncode
比较)。
我仍然不清楚——如果我没有转义整个 URI 而只是其中的一部分——(即查询字符串参数的 data)怎么办? ?我是在转义 URI 的数据,还是 EscapeDataString 暗示完全不同的东西?
... 做了一些测试,看起来我想要 EscapeDataString 作为 URI 参数。我用字符串“I heart C++”进行了测试,EscapeUriString 没有对“+”字符进行编码,它只是保持原样,EscapeDataString 正确地将它们转换为“%2B”。
这是一个糟糕的答案。你永远不应该使用 EscapeUriString,它没有任何意义。请参阅下面 Livven 的回答(并点赞)。【参考方案2】:
加号 (+) 字符可以揭示这些方法之间的很多区别。在简单的 URI 中,加号表示“空格”。考虑向 Google 查询“快乐猫”:
https://www.google.com/?q=happy+cat
这是一个有效的 URI(试试看),EscapeUriString
不会修改它。
现在考虑向 Google 查询“happy c++”:
https://www.google.com/?q=happy+c++
这是一个有效的 URI(试试看),但它会搜索“happy c”,因为这两个加号被解释为空格。要修复它,我们可以将“happy c++”传递给EscapeDataString
,然后瞧*:
https://www.google.com/?q=happy+c%2B%2B
*)编码后的数据串实际上是“happy%20c%2B%2B”; %20 是十六进制的空格字符,%2B 是十六进制的加号。
如果您按照应有的方式使用UriBuilder
,那么您只需要EscapeDataString
即可正确转义整个URI 的某些组件。 @Livven 对这个问题的回答进一步证明了确实没有理由使用EscapeUriString
。
【讨论】:
谢谢。如果您有一个需要编码的绝对 URI 字符串,例如"https://www.google.com/?q=happy c++"
,该怎么办。看起来我需要手动拆分“?”,还是有更好的方法?
如果您将整个 URL 作为参数传递给另一个 URL,请使用 EscapeDataString
。如果您提供的 URL 是实际 URL,那么是的,您只想拆分 ?
。【参考方案3】:
我没有找到令人满意的现有答案,因此我决定深入挖掘以解决此问题。令人惊讶的是,答案很简单:
(几乎)没有正当理由使用Uri.EscapeUriString
。如果您需要对字符串进行百分比编码,请始终使用Uri.EscapeDataString
。*
* 请参阅最后一段以了解有效的用例。
这是为什么?根据documentation:
使用 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,它会忽略保留字符,只转义既不是保留也不是非保留的字符,顺便说一句,这与 documentation 相反。这样您就不会遇到 http%3A%2F%2Fexample.org%2F
这样的问题,但您确实会遇到上述问题。
最后,如果你的 URI 是有效的,它不需要被转义作为参数传递给 Uri 构造函数,如果它无效,那么调用Uri.EscapeUriString
也不是一个神奇的解决方案。实际上,它在很多(如果不是大多数)情况下都可以使用,但它绝不是可靠的。
您应该始终通过收集键值对和百分比编码来构建您的 URL 和查询字符串,然后将它们与必要的分隔符连接起来。您可以为此目的使用Uri.EscapeDataString
,但不能使用Uri.EscapeUriString
,因为如上所述,它不会转义保留字符。
仅当您不能这样做时,例如在处理用户提供的 URI 时,是否有必要使用 Uri.EscapeUriString
作为最后的手段。但前面提到的警告也适用——如果用户提供的 URI 不明确,则结果可能不理想。
【讨论】:
哇,感谢您终于澄清了这个问题。前两个答案不是很有帮助。 完全正确。 EscapeUriString(类似于 Win32 中 EscapeUrl 的默认行为)是由不懂 URI 或转义的人创建的。创建采用格式错误的 URI 并有时将其转换为预期版本的东西是一种错误的尝试。但它没有可靠地执行此操作所需的信息。它也经常被用来代替 EscapeDataString,这也是非常有问题的。我希望 EscapeUriString 不存在。每次使用都是错误的。 很好地解释了+1,这比接受链接的答案要好得多 这个答案需要更多的关注。这是正确的方法。其他答案的情况不会产生预期的结果。 ...当然encodeURI
/Uri.EscapeUriString
不需要像encodeURIComponent
/Uri.EscapeDataString
那样频繁(因为您什么时候需要在uri 上下文中使用盲网址) ,但这并不意味着它没有它的位置。【参考方案4】:
source 中的评论清楚地说明了差异。为什么不通过 XML 文档 cmets 提供此信息对我来说是个谜。
EscapeUriString:
此方法将转义任何非保留字符或 无保留字符,包括百分号。注意 EscapeUriString 也不会转义“#”符号。
EscapeDataString:
此方法将转义任何不是未保留的字符 字符,包括百分号。
所以区别在于它们处理保留字符的方式。 EscapeDataString
逃脱它们; EscapeUriString
没有。
根据RFC,保留字符为::/?#[]@!$&'()*+,;=
为了完整起见,未保留的字符是字母数字和-._~
这两种方法都转义了既不是保留也不是非保留的字符。
我不同意notion 的普遍看法,即EscapeUriString
是邪恶的。我认为只转义 illegal 字符(例如空格)而不转义 reserved 字符的方法很有用。但它在处理%
字符的方式上确实有一个怪癖。百分比编码字符(%
后跟 2 个十六进制数字)在 URI 中是合法。我认为如果EscapeUriString
检测到这种模式并避免在%
立即以2 个十六进制数字进行编码时,它会更有用。
【讨论】:
【参考方案5】:一个简单的例子
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
*/
【讨论】:
【参考方案6】:我使用加密字符串作为 URL 参数(例如http://example.com/Test/myencryptedkey/param2/param3),因此没有任何 C# 加密方法可以提供安全的 url 参数。我最终使用了以下模式:
加密期间:
Uri.EscapeDataString(myencryptedkey).Replace('%', '~');
在解密期间:
Uri.UnescapeDataString(myencryptedkey.Replace('~', '%'));
请注意,在加密期间替换发生在 EscapeDataString() 之后,而在解密期间替换发生在 UnescapeDataString() 之前;
【讨论】:
以上是关于EscapeUriString 和 EscapeDataString 有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章
谷歌会将 hashbang/escaped_fragment 内容的正确 URL 编入索引吗
用字符串对列表赋值,一个字符串对应一个列表元素,eg: my @escaped = "asteriskasterisk hash access unpack_func";
使用具有不同参数的 Boost Tokenizer escaped_list_separator
python3中的encodedecodeunicode的使用以及unicode-escaped的使用
replace File.separator出现异常:java.lang.IllegalArgumentException: character to be escaped is missing((代