Uri.EscapeDataString 怪异

Posted

技术标签:

【中文标题】Uri.EscapeDataString 怪异【英文标题】:Uri.EscapeDataString weirdness 【发布时间】:2014-09-17 17:00:29 【问题描述】:

为什么 EscapeDataString 在 .NET 4 和 4.5 之间的行为不同?输出是

Uri.EscapeDataString("-_.!~*'()") => "-_.!~*'()"

Uri.EscapeDataString("-_.!~*'()") => "-_.%21~%2A%27%28%29"

The documentation

默认情况下,EscapeDataString 方法转换所有字符,除了 将 RFC 2396 未保留字符转换为十六进制 表示。如果国际资源标识符 (IRI) 或 启用国际化域名 (IDN) 解析, EscapeDataString 方法转换所有字符,除了 RFC 3986 未保留的字符,以它们的十六进制表示。全部 Unicode 字符在转义前转换为 UTF-8 格式。

供参考,RFC 2396中的非保留字符定义如下:

unreserved    = alphanum | mark

mark          = "-" | "_" | "." | "!" | "~" | "*" | "'" |
                (" | ")"

在RFC 3986:

ALPHA / DIGIT / "-" / "." / "_" / "~"

The source code

看起来EscapeDataString的每个字符是否被转义大致是这样确定的

is unicode above \x7F
  ? PERCENT ENCODE
  : is a percent symbol
    ? is an escape char
      ? LEAVE ALONE
      : PERCENT ENCODE
    : is a forced character
      ? PERCENT ENCODE
      : is an unreserved character
        ? PERCENT ENCODE

在最后检查“是非保留字符”时,会在 RFC2396 和 RFC3986 之间进行选择。该方法的源代码逐字为

    internal static unsafe bool IsUnreserved(char c)
    
        if (Uri.IsAsciiLetterOrDigit(c))
        
            return true;
        
        if (UriParser.ShouldUseLegacyV2Quirks)
        
            return (RFC2396UnreservedMarks.IndexOf(c) >= 0);
        
        return (RFC3986UnreservedMarks.IndexOf(c) >= 0);
    

那段代码指的是

    private static readonly UriQuirksVersion s_QuirksVersion = 
        (BinaryCompatibility.TargetsAtLeast_Desktop_V4_5
             // || BinaryCompatibility.TargetsAtLeast_Silverlight_V6
             // || BinaryCompatibility.TargetsAtLeast_Phone_V8_0
             ) ? UriQuirksVersion.V3 : UriQuirksVersion.V2;

    internal static bool ShouldUseLegacyV2Quirks 
        get 
            return s_QuirksVersion <= UriQuirksVersion.V2;
        
    

混乱

文档说 EscapeDataString 的输出取决于是否启用了 IRI/IDN 解析,而源代码说输出由 TargetsAtLeast_Desktop_V4_5 的值决定,这似乎是矛盾的。有人可以解决这个问题吗?

【问题讨论】:

这个问题帮助我弄清楚了为什么在 .Net 4.5 下我没有得到预期的行为,尽管我一开始并没有意识到。我应该更仔细地阅读源代码上的 cmets!谢谢!我的 *** 问题:***.com/questions/41006873/… 【参考方案1】:

与 4.0 相比,4.5 在系统功能和行为方式方面做了很多更改。 你可以看看这个帖子

Why does Uri.EscapeDataString return a different result on my CI server compared to my development machine?

你可以直接去以下链接

http://msdn.microsoft.com/en-us/library/hh367887(v=vs.110).aspx

所有这一切都来自世界各地用户的投入。

【讨论】:

以上是关于Uri.EscapeDataString 怪异的主要内容,如果未能解决你的问题,请参考以下文章

如何让 Uri.EscapeDataString 符合 RFC 3986

通过“HttpUtility.UrlEncode”和“Uri.EscapeDataString”在 GET API 请求中编码撇号会出错

EscapeUriString 和 EscapeDataString 有啥区别?

如何在 WinForms 中对 URL 进行编码?

BASE64编码的字符进行URL传输丢失特殊字符的问题

Owin的URL编码怎么搞?以前都是HttpUtility.UrlEncode之类的,现在连system.web都没了,肿么办?