本文提供了此 API 参考文档的补充说明。
统一资源标识符(URI)是 Intranet 或 Internet 上应用程序可用的资源的紧凑表示形式。 该 Uri 类定义用于处理 URI 的属性和方法,包括分析、比较和组合。 类 Uri 的属性是只读的;若要创建可修改的对象,请使用 UriBuilder 类。
相对 URI(例如,“/new/index.htm”)必须相对于基 URI 进行扩展,以便它们是绝对 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 方法将 ToString 类的内容从转义编码的 URI 引用转换为可读的 URI 引用。 请注意,在 ToString 方法的输出中,某些保留字符可能仍会被转义。 这是为了支持从返回 ToString的值中明确重建 URI。
某些 URI 包括片段标识符或查询或两者兼有。 片段标识符是数字符号(#)后面的任何文本,不包括数字符号;片段文本存储在属性中 Fragment 。 查询信息是 URI 中问号(?)后面的任何文本;查询文本存储在属性中 Query 。
注释
URI 类支持 IP 地址的使用,IPv4 协议使用四部分表示法,IPv6 协议使用冒号十六进制表示法。 请记住将 IPv6 地址括在方括号中,如 http://[::1]。
国际资源标识符支持
Web 地址通常使用 URI 表示,这些 URI 由一组非常受限的字符组成:
- 大写和小写的 ASCII 字母来自英文字母。
- 数字从 0 到 9。
- 少量其他 ASCII 符号。
URI 规范记录在 RFC 2396、RFC 2732、RFC 3986 和由 Internet 工程工作队(IETF)发布的 RFC 3987 中。
有助于使用英语以外的语言识别资源的标识符,并允许非 ASCII 字符(Unicode/ISO 10646 字符集中的字符)称为国际资源标识符(IRI)。 IETF 发布的 RFC 3987 中记录了 IRI 规范。 使用 IRIs 允许 URL 包含 Unicode 字符。
在 .NET Framework 4.5 及更高版本中,始终启用 IRI,无法使用配置选项进行更改。 可以在 machine.config 或 app.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 还可以更改 Equals、OriginalString、GetComponents 和 IsWellFormedOriginalString 方法的行为。
IDN 有三个可能的值,具体取决于使用的 DNS 服务器:
idn enabled = All
将任何 Unicode 域名转换为其 Punycode 等效项(IDN 名称)。
idn enabled = AllExceptIntranet
将所有不在本地 Intranet 上的 Unicode 域名转换为使用 Punycode 等效的 IDN 名称。 在这种情况下,若要处理本地 Intranet 上的国际名称,用于 Intranet 的 DNS 服务器应支持 Unicode 名称解析。
IDN 启用状态 = 无
不会将 Unicode 域名转换为使用 Punycode。 这是默认值。
规范化和字符检查是根据 RFC 3986 和 RFC 3987 中最新的 IRI 规则完成的。
可以使用Uri、System.Configuration.IriParsingElement 和 System.Configuration.IdnElement 配置设置类来控制 System.Configuration.UriSection 类中的 IRI 和 IDN 处理。 该 System.Configuration.IriParsingElement 设置启用或禁用 Uri 类中 IRI 处理。 System.Configuration.IdnElement 设置启用或禁用 Uri 类中的 IDN 处理。
首次构造System.Configuration.IriParsingElement类时,将对System.Configuration.IdnElement和System.Uri的配置设置进行一次性读取。 之后对配置设置的更改将被忽略。
该 System.GenericUriParser 类还进行了扩展,允许创建支持 IRI 和 IDN 的可自定义分析程序。 通过将System.GenericUriParser枚举中可用值的按位组合传递给System.GenericUriParserOptions构造函数,可以指定System.GenericUriParser对象的行为。 该 GenericUriParserOptions.IriParsing 类型指示分析程序支持 RFC 3987 中为国际资源标识符(IRI)指定的分析规则。
该 GenericUriParserOptions.Idn 类型指示分析程序支持主机名的国际化域名(IDN)分析。 在 .NET 5 及更高版本中(包括 .NET Core)和 .NET Framework 4.5+ 中,始终使用 IDN。 在以前的版本中,配置选项确定是否使用 IDN。
隐式文件路径支持
Uri 还可用于表示本地文件系统路径。 这些路径可以在以 file:// 方案开头的 URI 中 显式 表示,并在没有 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 时初始化应用程序受影响的部分,而不是在启动时。