public ref class Uri
public ref class Uri : System::Runtime::Serialization::ISerializable
public ref class Uri : MarshalByRefObject, System::Runtime::Serialization::ISerializable
public class Uri
public class Uri : System.Runtime.Serialization.ISerializable
[System.Serializable]
public class Uri : MarshalByRefObject, System.Runtime.Serialization.ISerializable
[System.Serializable]
[System.ComponentModel.TypeConverter(typeof(System.UriTypeConverter))]
public class Uri : System.Runtime.Serialization.ISerializable
type Uri = class
type Uri = class
    interface ISerializable
[<System.Serializable>]
type Uri = class
    inherit MarshalByRefObject
    interface ISerializable
[<System.Serializable>]
[<System.ComponentModel.TypeConverter(typeof(System.UriTypeConverter))>]
type Uri = class
    interface ISerializable
Public Class Uri
Public Class Uri
Implements ISerializable
Public Class Uri
Inherits MarshalByRefObject
Implements ISerializable
Object

以下示例创建 类的 Uri 一个实例,并使用它来通过 执行 GET 请求 HttpClient

Uri^ siteUri = gcnew Uri("http://www.contoso.com/"); // HttpClient lifecycle management best practices: // https://learn.microsoft.com/dotnet/fundamentals/networking/http/httpclient-guidelines#recommended-use HttpClient^ client = gcnew HttpClient; HttpRequestMessage^ request = gcnew HttpRequestMessage(HttpMethod::Get, siteUri); HttpResponseMessage^ response = client->Send(request); Uri siteUri = new Uri("http://www.contoso.com/"); // HttpClient lifecycle management best practices: // https://learn.microsoft.com/dotnet/fundamentals/networking/http/httpclient-guidelines#recommended-use HttpClient client = new HttpClient(); HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, siteUri); HttpResponseMessage response = client.Send(request); let siteUri = Uri "http://www.contoso.com/" // HttpClient lifecycle management best practices: // https://learn.microsoft.com/dotnet/fundamentals/networking/http/httpclient-guidelines#recommended-use use client = new HttpClient () use request = new HttpRequestMessage (HttpMethod.Get, siteUri) use response = client.Send request Dim siteUri As New Uri("http://www.contoso.com/") ' HttpClient lifecycle management best practices: ' https://learn.microsoft.com/dotnet/fundamentals/networking/http/httpclient-guidelines#recommended-use Dim client As New HttpClient() Dim request As New HttpRequestMessage(HttpMethod.Get, siteUri) Dim response As HttpResponseMessage = client.Send(request)

以下代码片段显示了 类上各种属性的示例值。

Uri uri = new Uri("https://user:password@www.contoso.com:80/Home/Index.htm?q1=v1&q2=v2#FragmentName"); Console.WriteLine($"AbsolutePath: {uri.AbsolutePath}"); Console.WriteLine($"AbsoluteUri: {uri.AbsoluteUri}"); Console.WriteLine($"DnsSafeHost: {uri.DnsSafeHost}"); Console.WriteLine($"Fragment: {uri.Fragment}"); Console.WriteLine($"Host: {uri.Host}"); Console.WriteLine($"HostNameType: {uri.HostNameType}"); Console.WriteLine($"IdnHost: {uri.IdnHost}"); Console.WriteLine($"IsAbsoluteUri: {uri.IsAbsoluteUri}"); Console.WriteLine($"IsDefaultPort: {uri.IsDefaultPort}"); Console.WriteLine($"IsFile: {uri.IsFile}"); Console.WriteLine($"IsLoopback: {uri.IsLoopback}"); Console.WriteLine($"IsUnc: {uri.IsUnc}"); Console.WriteLine($"LocalPath: {uri.LocalPath}"); Console.WriteLine($"OriginalString: {uri.OriginalString}"); Console.WriteLine($"PathAndQuery: {uri.PathAndQuery}"); Console.WriteLine($"Port: {uri.Port}"); Console.WriteLine($"Query: {uri.Query}"); Console.WriteLine($"Scheme: {uri.Scheme}"); Console.WriteLine($"Segments: {string.Join(", ", uri.Segments)}"); Console.WriteLine($"UserEscaped: {uri.UserEscaped}"); Console.WriteLine($"UserInfo: {uri.UserInfo}"); // AbsolutePath: /Home/Index.htm // AbsoluteUri: https://user:password@www.contoso.com:80/Home/Index.htm?q1=v1&q2=v2#FragmentName // DnsSafeHost: www.contoso.com // Fragment: #FragmentName // Host: www.contoso.com // HostNameType: Dns // IdnHost: www.contoso.com // IsAbsoluteUri: True // IsDefaultPort: False // IsFile: False // IsLoopback: False // IsUnc: False // LocalPath: /Home/Index.htm // OriginalString: https://user:password@www.contoso.com:80/Home/Index.htm?q1=v1&q2=v2#FragmentName // PathAndQuery: /Home/Index.htm?q1=v1&q2=v2 // Port: 80 // Query: ?q1=v1&q2=v2 // Scheme: https // Segments: /, Home/, Index.htm // UserEscaped: False // UserInfo: user:password let uri = Uri "https://user:password@www.contoso.com:80/Home/Index.htm?q1=v1&q2=v2#FragmentName" printfn $"AbsolutePath: {uri.AbsolutePath}" printfn $"AbsoluteUri: {uri.AbsoluteUri}" printfn $"DnsSafeHost: {uri.DnsSafeHost}" printfn $"Fragment: {uri.Fragment}" printfn $"Host: {uri.Host}" printfn $"HostNameType: {uri.HostNameType}" printfn $"IdnHost: {uri.IdnHost}" printfn $"IsAbsoluteUri: {uri.IsAbsoluteUri}" printfn $"IsDefaultPort: {uri.IsDefaultPort}" printfn $"IsFile: {uri.IsFile}" printfn $"IsLoopback: {uri.IsLoopback}" printfn $"IsUnc: {uri.IsUnc}" printfn $"LocalPath: {uri.LocalPath}" printfn $"OriginalString: {uri.OriginalString}" printfn $"PathAndQuery: {uri.PathAndQuery}" printfn $"Port: {uri.Port}" printfn $"Query: {uri.Query}" printfn $"Scheme: {uri.Scheme}" printfn $"""Segments: {String.Join(", ", uri.Segments)}""" printfn $"UserEscaped: {uri.UserEscaped}" printfn $"UserInfo: {uri.UserInfo}" // AbsolutePath: /Home/Index.htm // AbsoluteUri: https://user:password@www.contoso.com:80/Home/Index.htm?q1=v1&q2=v2#FragmentName // DnsSafeHost: www.contoso.com // Fragment: #FragmentName // Host: www.contoso.com // HostNameType: Dns // IdnHost: www.contoso.com // IsAbsoluteUri: True // IsDefaultPort: False // IsFile: False // IsLoopback: False // IsUnc: False // LocalPath: /Home/Index.htm // OriginalString: https://user:password@www.contoso.com:80/Home/Index.htm?q1=v1&q2=v2#FragmentName // PathAndQuery: /Home/Index.htm?q1=v1&q2=v2 // Port: 80 // Query: ?q1=v1&q2=v2 // Scheme: https // Segments: /, Home/, Index.htm // UserEscaped: False // UserInfo: user:password

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 进行转义。 如果启用了国际资源标识符或国际域名分析,则此行为会更改,在这种情况下,根据 RFC 3986 和 RFC 3987 对 URI 中的保留字符进行转义。

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

    var uri = new Uri("http://myUrl/../.."); // http scheme, unescaped
    var uri = new Uri("http://myUrl/%2E%2E/%2E%2E"); // http scheme, escaped
    var uri = new Uri("ftp://myUrl/../.."); // ftp scheme, unescaped
    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

    在 .NET Framework版本 1.1 中,如果向构造函数指定的字符串包含未知方案和“c:\”,则 Uri 类在冒号后插入“//”。 例如,URI xyz:c:\abc 转换为 xyz://c:/abc。 在 .NET Framework 版本 2.0 中,已删除此行为,并将示例字符串转换为 xyz:c:/abc

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

    国际资源标识符支持

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

  • 英文字母表中的大小写 ASCII 字母。

  • 从 0 到 9 的数字。

  • 少量的其他 ASCII 符号。

    INTERNET 工程任务组 (IETF) 发布的 RFC 2396、RFC 2732、RFC 3986 和 RFC 3987 中记录了 URI 规范。

    随着 Internet 的发展,越来越需要使用英语以外的语言识别资源。 标识符满足了这种需求,并且使得非 ASCII 字符(Unicode 中的字符/ISO 10646 字符集)被称为国际资源标识符(IRI)。 IETF 发布的 RFC 3987 记录了 IRI 的规格。 使用 IRI 允许 URL 包含 Unicode 字符。

    .NET Framework v3.5、3.0 SP1 和 2.0 SP1 中扩展了现有Uri类,以提供基于 RFC 3987 的 IRI 支持。 .NET Framework版本 4.5 之前的用户不会看到.NET Framework 2.0 行为的任何更改,除非他们专门启用 IRI。 这可确保应用程序与以前版本的 .NET Framework 兼容。

    在 .NET Framework 4.5 及更高版本中,IRI 始终处于启用状态,无法使用配置选项进行更改。 若要在 .NET Framework 4.5 之前的 .NET Framework 版本中启用对 IRI 的支持,请在 machine.configapp.config 文件中设置配置选项。 指定是否要对域名应用国际化域名 (IDN) 分析,以及是否应该应用 IRI 分析规则。 例如:

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

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

    启用 IRI 和 IDN 会影响 Uri.DnsSafeHost 属性的值。 启用 IRI 和 IDN 还可能更改 EqualsOriginalStringGetComponentsIsWellFormedOriginalString 方法的行为。

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

  • idn enabled = All

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

  • idn enabled = AllExceptIntranet

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

  • idn enabled = None

    此值不会将任何 Unicode 域名转换为使用 Punycode。 这是与 .NET Framework 2.0 行为一致的默认值。

    当启用 IRI 分析 (启用 iriParsing = true) 时,将根据 RFC 3986 和 RFC 3987 中的最新 IRI 规则进行规范化和字符检查。 禁用 IRI 分析后,将根据 RFC 2396 和 RFC 2732 (对 IPv6 文本) 执行规范化和字符检查。 在版本 4.5 之前的 .NET Framework 版本中,默认值为 false。 在 .NET Framework 4.5+、.NET Core 和 .NET 5+ 中,默认值true为 ,并且 IRI 分析的启用状态不能由.config文件中的设置修改。

    类中的 Uri IRI 和 IDN 处理也可以使用 、 System.Configuration.IdnElementSystem.Configuration.UriSection 配置设置类进行System.Configuration.IriParsingElement控制。 System.Configuration.IriParsingElement 设置启用或禁用 Uri 类中的 IRI 处理。 System.Configuration.IdnElement 设置启用或禁用 Uri 类中的 IDN 处理。 System.Configuration.IriParsingElement 也可间接控制 IDN。 必须启用 IRI 处理才能进行 IDN 处理。 如果禁用 IRI,IDN 处理将被设置为默认值,这时 NET Framework 2.0 行为用于兼容性,并且 IDN 名称不可用。

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

    System.GenericUriParser 类已得到扩展,允许创建支持 IRI 和 IDN 的自定义分析。 通过将枚举中可用值的按位组合传递给 System.GenericUriParserOptions 构造函数 System.GenericUriParser 来指定 System.GenericUriParser 对象的行为。 GenericUriParserOptions.IriParsing 类型表示分析程序支持 RFC 3987 中为国际资源标识符 (IRI) 指定的分析规则。 是否使用 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 时(而不是在开始时间)初始化应用程序的受影响部分。

  •