如果只处理url编码,我应该使用EscapeUriString?


当前回答

源代码中的注释清楚地说明了这一差异。为什么这些信息没有通过XML文档注释提出,这对我来说是个谜。

EscapeUriString:

此方法将转义不是保留或的任何字符 无保留字符,包括百分号。请注意, EscapeUriString也不会转义'#'符号。

EscapeDataString:

此方法将转义任何非unreserved字符 字符,包括百分号。

不同之处在于它们如何处理保留字符。EscapeDataString转义它们;EscapeUriString没有。

根据RFC,保留字符为::/?#[]@!$&'()*+,;=

为完整起见,无保留字符为字母数字和-._~

这两种方法都转义既不是保留字符也不是非保留字符。

我不同意认为EscapeUriString是邪恶的一般概念。我认为只转义非法字符(如空格)而不转义保留字符的方法是有用的。但是它在如何处理%字符方面确实有一个怪癖。百分比编码字符(%后面跟着2个十六进制数字)在URI中是合法的。我认为EscapeUriString会更有用,如果它检测到这种模式,并避免编码%时,立即进行2个十六进制数字。

其他回答

始终使用EscapeDataString(有关原因的更多信息,请参阅下面Livven的答案)

编辑:删除死链接,以了解两者在编码上的差异

加号(+)可以揭示这些方法之间的很多差异。在简单的URI中,加号表示“空格”。考虑查询谷歌中的“happy cat”:

https://www.google.com/?q=happy+cat

这是一个有效的URI(尝试一下),EscapeUriString不会修改它。

现在考虑用谷歌查询"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.EscapeUriString的正当理由。如果你需要对字符串进行百分比编码,总是使用Uri.EscapeDataString.*

*请参阅最后一段的有效用例。

为什么会这样?根据文档:

使用EscapeUriString方法准备一个未转义的URI字符串作为URI构造函数的参数。

这真的说不通。根据RFC 2396:

URI总是采用“转义”形式,因为转义或不转义一个完整的URI可能会改变它的语义。

虽然引用的RFC已经被RFC 3986淘汰,但这一点仍然成立。让我们通过一些具体的例子来验证一下:

你有一个简单的URI,像这样: http://example.org/

Uri。EscapeUriString不会改变它。

你决定手动编辑查询字符串而不考虑转义: http://example.org/?key=two的话

Uri。EscapeUriString将(正确地)为你转义空间:

    http://example.org/?key=two%20words

您决定手动编辑查询字符串进一步: http://example.org/?parameter=father&son

但是,Uri不会改变这个字符串。EscapeUriString,因为它假设&符号表示另一个键-值对的开始。这可能是也可能不是你想要的。

你决定你实际上想要的关键参数是父子,所以你手动修复前面的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是模棱两可的,结果可能不是理想的。

我使用一个加密的字符串作为Url参数(例如http://example.com/Test/myencryptedkey/param2/param3),所以没有c#加密方法可以提供一个安全的Url参数。我最终使用了以下模式:

在加密: Uri.EscapeDataString (myencryptedkey)。取代 ('%', '~');

在解密: Uri.UnescapeDataString (myencryptedkey。取代 ('~', '%'));

注意,在加密期间,替换发生在EscapeDataString()之后,而在解密期间,替换发生在UnescapeDataString()之前;

源代码中的注释清楚地说明了这一差异。为什么这些信息没有通过XML文档注释提出,这对我来说是个谜。

EscapeUriString:

此方法将转义不是保留或的任何字符 无保留字符,包括百分号。请注意, EscapeUriString也不会转义'#'符号。

EscapeDataString:

此方法将转义任何非unreserved字符 字符,包括百分号。

不同之处在于它们如何处理保留字符。EscapeDataString转义它们;EscapeUriString没有。

根据RFC,保留字符为::/?#[]@!$&'()*+,;=

为完整起见,无保留字符为字母数字和-._~

这两种方法都转义既不是保留字符也不是非保留字符。

我不同意认为EscapeUriString是邪恶的一般概念。我认为只转义非法字符(如空格)而不转义保留字符的方法是有用的。但是它在如何处理%字符方面确实有一个怪癖。百分比编码字符(%后面跟着2个十六进制数字)在URI中是合法的。我认为EscapeUriString会更有用,如果它检测到这种模式,并避免编码%时,立即进行2个十六进制数字。