System.Uri 类

本文提供了此 API 参考文档的补充说明。

URI 是 Intranet 或 Internet 上应用程序可用的资源的紧凑表示形式。 该 Uri 类定义用于处理 URI 的属性和方法,包括分析、比较和组合。 类属性是只读的 Uri ;若要创建可修改的对象,请使用该 UriBuilder 类。

相对于基 URI(例如,“/new/index.htm”)必须扩展,以便它们是绝对 URI。 MakeRelativeUri提供此方法,以便在必要时将绝对 URI 转换为相对 URI。

如果字符串是格式正确的 URI(包括方案标识符),则 Uri 构造函数不会转义 URI 字符串。

这些 Uri 属性以转义编码返回规范数据表示形式,其 Unicode 值大于 127 的所有字符都替换为其十六进制等效项。 若要以规范形式放置 URI, Uri 构造函数将执行以下步骤:

  • 将 URI 方案转换为小写。

  • 将主机名转换为小写。

  • 如果主机名是 IPv6 地址,则使用规范 IPv6 地址。 ScopeId 和其他可选 IPv6 数据已删除。

  • 删除默认端口号和空端口号。

  • 将不使用 file:// 方案(例如“C:\my\file”)的隐式文件路径转换为具有 file:// 方案的显式文件路径。

  • 转义字符(也称为未保留用途的百分比编码八进制数)将被解码(也称为未转义)。 这些未保留字符包括大写字母和小写字母(%41-%5A 和 %61-%7A)、十进制数字(%30-%39)、连字符(%2D)、句点(%2E)、下划线(%5F)和波形符(%7E)。

  • 通过压缩 /./、 /.等序列来规范分层 URI 的路径。/, 和 // (是否转义序列)。 请注意,某些方案未压缩这些序列。

  • 对于分层 URI,如果主机未以正斜杠(/)终止,则会添加一个。

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

作为某些方案的构造函数规范化的一部分,将压缩点段和空段(以及//)(/.//../换句话说,删除它们)。 压缩段的方案 Uri 包括 http、https、tcp、net.pipe 和 net.tcp。 对于某些其他方案,这些序列不会压缩。 以下代码片段演示了实际压缩的外观。 如果有必要,则转义的序列将被取消转义,然后压缩。

var uri = new Uri("http://myUrl/../.."); // http scheme, unescaped
OR
var uri = new Uri("http://myUrl/%2E%2E/%2E%2E"); // http scheme, escaped
OR
var uri = new Uri("ftp://myUrl/../.."); // ftp scheme, unescaped
OR
var uri = new Uri("ftp://myUrl/%2E%2E/%2E%2E"); // ftp scheme, escaped

Console.WriteLine($"AbsoluteUri: {uri.AbsoluteUri}");
Console.WriteLine($"PathAndQuery: {uri.PathAndQuery}");

执行此代码时,它将返回类似于以下文本的输出。

AbsoluteUri: http://myurl/
PathAndQuery: /

可以使用该方法将类的内容 Uri 从转义编码的 URI 引用转换为可读 URI 引用 ToString 。 请注意,方法的输出 ToString 中仍可能会转义某些保留字符。 这是为了支持从返回 ToString的值中明确重建 URI。

某些 URI 包括片段标识符或查询或两者兼有。 片段标识符是数字符号(#)后面的任何文本,不包括数字符号;片段文本存储在属性中 Fragment 。 查询信息是 URI 中问号(?)后面的任何文本;查询文本存储在属性中 Query

注意

URI 类支持在 IPv4 协议的四元表示法中使用 IP 地址,以及 IPv6 协议的冒号十六进制地址。 请记住将 IPv6 地址括在方括号中,如 http://[::1]。

国际资源标识符支持

Web 地址通常使用统一资源标识符表示,这些标识符由一组非常受限的字符组成:

  • 英文字母表中的大小写 ASCII 字母。
  • 从 0 到 9 的数字。
  • 少量的其他 ASCII 符号。

URI 规范记录在 RFC 2396、RFC 2732、RFC 3986 和由 Internet 工程工作队(IETF)发布的 RFC 3987 中。

有助于使用英语以外的语言识别资源的标识符,并允许非 ASCII 字符(Unicode/ISO 10646 字符集中的字符)称为国际资源标识符(IRI)。 IETF 发布的 RFC 3987 记录了 IRI 的规格。 使用 IRI 允许 URL 包含 Unicode 字符。

在 .NET Framework 4.5 及更高版本中,始终启用 IRI,无法使用配置选项进行更改。 可以在 machine.configapp.config 文件中设置配置选项,以指定是否希望对应用于域名的国际化域名(IDN)进行分析。 例如:

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

启用 IDN 会将域名中的所有 Unicode 标签转换为其 Punycode 等效项。 Punycode 名称只包含 ASCII 字符,并且始终以 xn-- 前缀开头。 这样是为了支持 Internet 上的 DNS 服务器,因为大部分 DNS 服务器仅支持 ASCII 字符(参见 RFC 3940)。

启用 IDN 会影响属性的值 Uri.DnsSafeHost 。 启用 IDN 还可以更改 OriginalStringGetComponents> 和IsWellFormedOriginalString方法的行为Equals

根据所用的 DNS 服务器,IDN 有三个可能的值:

  • idn enabled = All

    此值会将所有 Unicode 域名转换为它们的 Punycode 等效项(IDN 名称)。

  • idn enabled = AllExceptIntranet

    此值将转换所有不在本地 Intranet 上的 Unicode 域名以使用 Punycode 等效项(IDN 名称)。 在这种情况下,若要处理本地 Intranet 上的国际化名称,用于 Intranet 的 DNS 服务器应该支持 Unicode 名称解析。

  • idn enabled = None

    此值不会将任何 Unicode 域名转换为使用 Punycode。 这是默认值。

规范化和字符检查根据 RFC 3986 和 RFC 3987 中的最新 IRI 规则完成。

还可以使用System.Configuration.IriParsingElementSystem.Configuration.IdnElement和配置设置类来控制类中的 Uri IRI 和 System.Configuration.UriSection IDN 处理。 System.Configuration.IriParsingElement 设置启用或禁用 Uri 类中的 IRI 处理。 System.Configuration.IdnElement 设置启用或禁用 Uri 类中的 IDN 处理。

构造第一System.Uri个类时,将System.Configuration.IdnElement读取该配置设置System.Configuration.IriParsingElement并读取一次。 忽略时间后更改为默认设置。

System.GenericUriParser 类已得到扩展,允许创建支持 IRI 和 IDN 的自定义分析。 通过将枚举中可用值的按位组合传递给 System.GenericUriParserOptions 构造函数 System.GenericUriParser 来指定 System.GenericUriParser 对象的行为。 GenericUriParserOptions.IriParsing 类型表示分析程序支持 RFC 3987 中为国际资源标识符 (IRI) 指定的分析规则。

GenericUriParserOptions.Idn 类型指示分析程序支持主机名的国际化域名(IDN)分析。 在 .NET 5 及更高版本中(包括 .NET Core)和 .NET Framework 4.5+ 中,始终使用 IDN。 在以前的版本中,配置选项确定是否使用 IDN。

隐式文件路径支持

Uri 还可用于表示本地文件系统路径。 这些路径可以在 URI 中显式表示,这些路径以 file:// 方案开头,并在没有 file:// 方案的 URI 中隐式表示。 作为具体示例,以下两个 URI 均有效,并表示相同的文件路径:

Uri uri1 = new Uri("C:/test/path/file.txt") // Implicit file path.
Uri uri2 = new Uri("file:///C:/test/path/file.txt") // Explicit file path.

这些隐式文件路径不符合 URI 规范,因此应尽可能避免。 在基于 Unix 的系统上使用 .NET Core 时,隐式文件路径可能会特别有问题,因为绝对隐式文件路径与 相对路径不可 区分。 如果存在此类歧义, Uri 则默认将路径解释为绝对 URI。

安全注意事项

由于安全问题,应用程序在接受Uri来自不受信任的源的实例并在dontEscape构造函数设置为true时应谨慎使用。 可以通过调用IsWellFormedOriginalString该方法来检查 URI 字符串的有效性。

在处理不受信任的用户输入时,在信任新创建的 Uri 实例之前确认其属性的假设。 这可以通过以下方式完成:

string userInput = ...;

Uri baseUri = new Uri("https://myWebsite/files/");

if (!Uri.TryCreate(baseUri, userInput, out Uri newUri))
{
    // Fail: invalid input.
}

if (!baseUri.IsBaseOf(newUri))
{
    // Fail: the Uri base has been modified - the created Uri is not rooted in the original directory.
}

此验证可用于其他情况,例如处理 UNC 路径时,只需更改 baseUri以下内容即可:

Uri baseUri = new Uri(@"\\host\share\some\directory\name\");

性能注意事项

如果使用 包含 URI 的 Web.config文件来初始化应用程序,则如果 URI 方案标识符不标准,则需要额外的时间来处理 URI。 在这种情况下,在需要 URI 时初始化应用程序受影响的部分,而不是在启动时。