C# URI 介紹,網址拆分、拼接、URL encode, decode 教學

URI(統一資源標識符) 是用來表示網路上的資源,C# 中的 System.Uri 類別能夠用來取得 URI 各部分的資訊和連接,避免手動把連結當作字串的方式處理會遇到的不知道到底有沒有斜線的問題。

System.Uri 基本參數

範例:
    
System.Uri uri = new System.Uri("https://localhost:44300/api/Values/1?q=a#f1");
Console.WriteLine($"uri: {uri}"); // 完整網址
Console.WriteLine($"Scheme: {uri.Scheme}"); // 通訊協議
Console.WriteLine($"Host: {uri.Host}"); // 主機名稱
Console.WriteLine($"Port: {uri.Port}"); // 連接埠
Console.WriteLine($"PathAndQuery: {uri.PathAndQuery}"); // 路徑與查詢字串
Console.WriteLine($"AbsolutePath: {uri.AbsolutePath}"); // 絕對路徑
Console.WriteLine($"LocalPath: {uri.LocalPath}"); // 本地路徑
Console.WriteLine($"Query: {uri.Query}"); // 查詢字串
Console.WriteLine($"Fragment: {uri.Fragment}"); // 標記
    

輸出結果:
    
uri: https://localhost:44300/api/Values/1?q=a#f1
Scheme: https
Host: localhost
Port: 44300
PathAndQuery: /api/Values/1?q=a
AbsolutePath: /api/Values/1
LocalPath: /api/Values/1
Query: ?q=a
Fragment: #f1
    

疑? 絕對路徑(AbsolutePath)和本地路徑(LocalPath)看起來一樣啊? 差別在哪裡?

經過研究後發現,和本地路徑就是經過轉譯的絕對路徑,看看下面的範例:
    
uri: https://m.ruyut.app/軟體?q=軟體
Scheme: https
Host: m.ruyut.app
Port: 443
PathAndQuery: /%E8%BB%9F%E9%AB%94?q=%E8%BB%9F%E9%AB%94
AbsolutePath: /%E8%BB%9F%E9%AB%94
LocalPath: /軟體
Query: ?q=%E8%BB%9F%E9%AB%94
    

PathAndQuery, AbsolutePath 和 Query 都亂成一團,就只有 LocalPath 經過轉換,能夠最方便的呈現給使用者看。

URL 解碼(URL decoding)

那 Query 呢? 他可以轉換嗎? 當然!
    
string decodedQuery = Uri.UnescapeDataString(uri.Query); // "?q=%E8%BB%9F%E9%AB%94"
Console.WriteLine($"decodedQuery: {decodedQuery}"); // "?q=軟體"

string encodedQuery = Uri.EscapeDataString(uri.Query);
Console.WriteLine($"encodedQuery: {encodedQuery}"); // "%3Fq%3D%25E8%25BB%259F%25E9%25AB%2594"
    

拆分查詢字串(QueryString)

其實還有另一個更方便的方法:
有時候查詢字串會有多個,使用 Http 幫助類中的 ParseQueryString 方法能夠幫我們把查詢參數拆分成鍵值(key:value)的集合,並且也會自動幫我們解碼:
    
Uri uri = new Uri("https://m.ruyut.app/api/v1/a?q=%E8%BB%9F%E9%AB%94&q1=a1&q2=a2");
Console.WriteLine($"uri: {uri}"); // 完整網址
Console.WriteLine($"Query: {uri.Query}"); // 查詢字串
NameValueCollection queryValues = HttpUtility.ParseQueryString(uri.Query);

foreach (string? key in queryValues.AllKeys)
{
    Console.WriteLine("{0}: {1}", key, queryValues[key]);
}
    

輸出:
    
uri: https://m.ruyut.app/api/v1/a?q=軟體&q1=a1&q2=a2
Query: ?q=%E8%BB%9F%E9%AB%94&q1=a1&q2=a2
q: 軟體
q1: a1
q2: a2

    

網址串接

有時候需要把網址寫在設定檔或是以其他方式讓使用者輸入,然後組出網址,萬一使用者在最後面多了一個斜線或是少了一個斜線怎麼辦?

我們可以使用 Uri 這個類別來連接網址,而不是使用字串拼接:
    
Uri uri1 = new Uri("https://m.ruyut.app");
Uri uri2 = new Uri("https://m.ruyut.app/");

string path1 = "api/test/1";
string path2 = "/api/test/1";

Console.WriteLine(new Uri(uri1, path1)); // https://m.ruyut.app/api/test/1
Console.WriteLine(new Uri(uri1, path2)); // https://m.ruyut.app/api/test/1
Console.WriteLine(new Uri(uri2, path1)); // https://m.ruyut.app/api/test/1
Console.WriteLine(new Uri(uri2, path2)); // https://m.ruyut.app/api/test/1
    

經過簡單的測試,不論基礎網址(Host)後面有沒有斜線,路徑(Path)前面有沒有斜線,都能夠很聰明的連接。

Uri 非常方便,不過有個小小的缺點,就是無法編輯。那需要調整連結該怎麼辦? 這就是 System.UriBuilder 派上用場的時候了!
延伸閱讀:C# UriBuilder 介紹:自由的變更網址連結

留言