如何让 Uri.EscapeDataString 符合 RFC 3986 [英] How to get Uri.EscapeDataString to comply with RFC 3986

查看:17
本文介绍了如何让 Uri.EscapeDataString 符合 RFC 3986的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Uri 类默认为 RFC 2396.对于 OpenID 和 OAuth,我需要与 RFC 3986 一致的 Uri 转义.

来自 System.Uri 类文档:<块引用>

默认情况下,URI 中的任何保留字符都根据 RFC 2396 进行转义.如果启用了国际资源标识符或国际域名解析,则此行为会发生变化,在这种情况下,URI 中的保留字符将根据 RFC 3986 和RFC 3987.

文档还指出,激活此 IRI 模式以及 RFC 3986 行为意味着将 uri 部分元素添加到 machine.config 并将其添加到您的 app/web.config 文件:

<预><代码><配置><uri><idn enabled="全部"/><iriParsing enabled="true"/></uri></配置>

但是,无论这是否存在于 .config 文件中,对于 .NET 3.5 SP1 应用程序,我都会得到相同的(非 3986)转义行为.我还需要做什么才能让 Uri.EscapeDataString 使用 RFC 3986 规则?(具体来说,要转义该 RFC 中定义的保留字符)

解决方案

由于无法让 Uri.EscapeDataString 承担 RFC 3986 行为,我编写了自己的符合 RFC 3986 的转义方法.它利用 Uri.EscapeDataString,然后将转义升级"到 RFC 3986 合规性.

////<摘要>///在 RFC 2396 中未保留但在 RFC 3986 中未保留的字符集.///</总结>private static readonly string[] UriRfc3986CharsToEscape = new[] { "!", "*", "'", "(", ")" };///<总结>///根据 RFC 3986 中给出的 URI 数据字符串规则对字符串进行转义.///</总结>///<param name="value">要转义的值.</param>///<returns>转义的值.</returns>///<备注>///<see cref="Uri.EscapeDataString"/>方法是<i>假定</i>承担///如果某些元素存在于 .config 文件中,则 RFC 3986 行为.即使这///实际上有效(在我的实验中它没有),我们不能依赖每个///主机实际上存在此配置元素.///</备注>内部静态字符串 EscapeUriDataStringRfc3986(字符串值){//从 RFC 2396 转义开始,调用 .NET 方法来完成这项工作.//这有时可能会表现出 RFC 3986 行为(根据文档).//如果是,我们接下来的转义将是一个空操作,因为//我们搜索替换的字符不可能存在于字符串中.StringBuilder 转义 = new StringBuilder(Uri.EscapeDataString(value));//如有必要,将转义升级到 RFC 3986.for (int i = 0; i < UriRfc3986CharsToEscape.Length; i++) {escaped.Replace(UriRfc3986CharsToEscape[i], Uri.HexEscape(UriRfc3986CharsToEscape[i][0]));}//返回完全 RFC3986 转义的字符串.返回转义.ToString();}

The Uri class defaults to RFC 2396. For OpenID and OAuth, I need Uri escaping consistent with RFC 3986.

From the System.Uri class documentation:

By default, any reserved characters in the URI are escaped in accordance with RFC 2396. This behavior changes if International Resource Identifiers or International Domain Name parsing is enabled in which case reserved characters in the URI are escaped in accordance with RFC 3986 and RFC 3987.

The documentation also states that activating this IRI mode and thus the RFC 3986 behavior means adding a uri section element to machine.config and this to your app/web.config file:

<configuration>
  <uri>
  <idn enabled="All" />
  <iriParsing enabled="true" />
  </uri>
</configuration>

But whether this is present in the .config file or not, I'm getting the same (non-3986) escaping behavior for a .NET 3.5 SP1 app. What else do I need to do to get Uri.EscapeDataString to use the RFC 3986 rules? (specifically, to escape the reserved characters as defined in that RFC)

解决方案

Having not been able to get Uri.EscapeDataString to take on RFC 3986 behavior, I wrote my own RFC 3986 compliant escaping method. It leverages Uri.EscapeDataString, and then 'upgrades' the escaping to RFC 3986 compliance.

/// <summary>
/// The set of characters that are unreserved in RFC 2396 but are NOT unreserved in RFC 3986.
/// </summary>
private static readonly string[] UriRfc3986CharsToEscape = new[] { "!", "*", "'", "(", ")" };

/// <summary>
/// Escapes a string according to the URI data string rules given in RFC 3986.
/// </summary>
/// <param name="value">The value to escape.</param>
/// <returns>The escaped value.</returns>
/// <remarks>
/// The <see cref="Uri.EscapeDataString"/> method is <i>supposed</i> to take on
/// RFC 3986 behavior if certain elements are present in a .config file.  Even if this
/// actually worked (which in my experiments it <i>doesn't</i>), we can't rely on every
/// host actually having this configuration element present.
/// </remarks>
internal static string EscapeUriDataStringRfc3986(string value) {
    // Start with RFC 2396 escaping by calling the .NET method to do the work.
    // This MAY sometimes exhibit RFC 3986 behavior (according to the documentation).
    // If it does, the escaping we do that follows it will be a no-op since the
    // characters we search for to replace can't possibly exist in the string.
    StringBuilder escaped = new StringBuilder(Uri.EscapeDataString(value));

    // Upgrade the escaping to RFC 3986, if necessary.
    for (int i = 0; i < UriRfc3986CharsToEscape.Length; i++) {
        escaped.Replace(UriRfc3986CharsToEscape[i], Uri.HexEscape(UriRfc3986CharsToEscape[i][0]));
    }

    // Return the fully-RFC3986-escaped string.
    return escaped.ToString();
}

这篇关于如何让 Uri.EscapeDataString 符合 RFC 3986的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆