如果只处理url编码,我应该使用EscapeUriString?
加号(+)可以揭示这些方法之间的很多差异。在简单的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是模棱两可的,结果可能不是理想的。
源代码中的注释清楚地说明了这一差异。为什么这些信息没有通过XML文档注释提出,这对我来说是个谜。
EscapeUriString:
此方法将转义不是保留或的任何字符 无保留字符,包括百分号。请注意, EscapeUriString也不会转义'#'符号。
EscapeDataString:
此方法将转义任何非unreserved字符 字符,包括百分号。
不同之处在于它们如何处理保留字符。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
*/
我使用一个加密的字符串作为Url参数(例如http://example.com/Test/myencryptedkey/param2/param3),所以没有c#加密方法可以提供一个安全的Url参数。我最终使用了以下模式:
在加密: Uri.EscapeDataString (myencryptedkey)。取代 ('%', '~');
在解密: Uri.UnescapeDataString (myencryptedkey。取代 ('~', '%'));
注意,在加密期间,替换发生在EscapeDataString()之后,而在解密期间,替换发生在UnescapeDataString()之前;
推荐文章
- AutoMapper:“忽略剩下的?”
- 如何找出一个文件存在于c# / .NET?
- string. isnullorempty (string) vs. string. isnullowhitespace (string)
- 完全外部连接
- URLEncoder不能翻译空格字符
- 如何使用。net 4运行时运行PowerShell ?
- 在foreach循环中编辑字典值
- 使用System.IO.Compression在内存中创建ZIP存档
- 在WPF中引入一个窗口到前面
- .NET用固定的空格格式化字符串
- 我如何获得和设置环境变量在c# ?
- Linq风格的“For Each”
- 我如何得到一个动画gif在WPF工作?
- 什么时候使用记录、类和结构
- 获取程序集名称