System.Uri 類別

本文提供此 API 參考文件的補充備註。

URI 是內部網路或因特網上應用程式可用的資源精簡表示法。 類別 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]。

國際資源標識碼支援

網址通常會使用統一資源標識符來表示,其中包含一組非常受限的字元:

  • 大寫和小寫的英文 ASCII 字母。
  • 0 到 9 位數。
  • 少數幾個其他 ASCII 符號。

URI 的規格記載於 INTERNET Engineering Task Force (IETF) 發佈的 RFC 2396、RFC 2732、RFC 3986 和 RFC 3987。

使用英文以外的語言識別資源,並允許非 ASCII 字元(Unicode/ISO 10646 字元集中的字元)稱為「國際資源標識碼」的識別碼。 IETF 發行的 RFC 3987 中有記載 IRI 的規格。 使用 IRI 可讓 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--。 這是為了支援網際網路上現有的 DNS 伺服器,因為大部分的 DNS 伺服器僅支援 ASCII 字元 (請參閱 RFC 3940)。

啟用IDN會影響屬性的值 Uri.DnsSafeHost 。 啟用IDN也可以變更、OriginalStringGetComponentsIsWellFormedOriginalString 方法的行為Equals

根據所使用的 DNS 伺服器而定,IDN 有三個可能的值:

  • idn enabled = All

    此值會將任何 Unicode 功能變數名稱轉換成其 Punycode 對等專案 (IDN 名稱)。

  • idn enabled = AllExceptIntranet

    此值會將本機內部網路上的所有 Unicode 功能變數名稱轉換成使用 Punycode 對等專案 (IDN 名稱)。 在此情況下,若要處理近端內部網路上的國際名稱,用於內部網路的 DNS 伺服器應該支援 Unicode 名稱解析。

  • idn enabled = None

    此值不會將任何 Unicode 功能變數名稱轉換成使用 Punycode。 這是預設值。

正規化和字元檢查是根據 RFC 3986 和 RFC 3987 中最新的 IRI 規則來完成。

類別中的 Uri IRI 和 IDN 處理也可以使用、 System.Configuration.IdnElementSystem.Configuration.UriSection 組態設定類別來控制System.Configuration.IriParsingElementSystem.Configuration.IriParsingElement 設定可啟用或停用 Uri 類別中的 IRI 處理。 System.Configuration.IdnElement 設定可啟用或停用 Uri 類別中的 IDN 處理。

建構第一System.Uri個類別時,和 System.Configuration.IdnElement 的組態設定System.Configuration.IriParsingElement會讀取一次。 該時間之後的組態設定變更會被忽略。

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 時,初始化應用程式受影響的部分,而不是在開始時間。