2021.07.27 增加寶典-URI 設計原則
ASP.NET Web API 是一種架構,可讓您更輕鬆建置 HTTP 服務並擴及各種用戶端,包括瀏覽器和行動裝置。 ASP.NET Web 應用程式開發介面是在 .NET Framework 上建置 RESTful 應用程式的理想平台。
URI 統一資源識別元 (Uniform Resource Identifiers,URI) 1
scheme:[//[user[:password]@]host[:port]][/path][?query][#fragment]
- host:溝通系統的 resource,對 HTTP 而言就是 Web Server
- port:Tcp port,一般HTTP使用80
- query:Resource 或 Client 的額外資訊
- fragment:Resource的 特定位置
- URI 必須透過名稱解析服務 (ex: DNS),找到 Server (或 代理、閘道、負載平衡器) 的 IP 位址,並藉此訪問
URI 設計原則
- 簡短便於輸入的 URI:
- 去除無意義且重覆的單詞,例如 https://api.example.com/api/v1/employees,由 domain 就能得知這是一個 API,但在路徑又重覆了一次 api。
- 使用者能讀懂的 URI:
- 使用有意義的英文單字,而不使用縮寫。
- 小寫英文字母的 URI:
- 一律使用小寫英文字母,更不可大小寫字母混用。
- 修改方便的 URI:
- 例如 https://api.example.com/v1/employees/1,即可看出該員工 ID 為 1,而且只要修改 ID 就能獲取其他員工的資源。
- 不暴露 server 架構的 URI:
- 例如 https://api.example.com/v1/employees.php,就知道應該是用 PHP 程式語言編寫的,這讓黑客更容易針對漏洞發起惡意攻擊。
- 規則統一的 URI:
- 例如使用英文字母複數 https://api.example.com/v1/employees 來取得所有員工資源組
- 用單數 https://api.example.com/v1/employee/1 來取得一位員工的資源,類似這種不統一的 URI 容易造成 client 的混亂。 不使用空格及需要編碼的字元。 使用連接符 - 連結多個英文單字: 但應避免多個英文單字連結,而是使用路徑 / 劃分的方式。 URI 應加入 API 的版本號: 如 https://api.example.com/v1/employees。
▍API 設計範例
方法 | 一組資源 URI:https://api.example.com/v1/employees | 單個資源 URI:https://api.example.com/v1/employees/1 |
---|---|---|
GET | 取得資源組 (所有資料) | 取得指定的一筆資源 |
POST | 新增一筆資源 | |
PUT | 覆蓋指定的一筆資源 | |
PATCH | 更新指定的一筆資源 (部份更新) | |
DELETE | 刪除指定的一筆資源 |
▍資料筆數與位置查詢參數 資料量如果很多的話,API 就要設計成能夠指定欲取得的資料筆數 limit 和資料位置 offset or max_id,這兩個查詢參數也是 client 實現分頁機制所須要的。
項目 | 查詢參數名稱 | 參數值 | 說明 | 備註 |
---|---|---|---|---|
資料筆數 | limit | 5 | 每次取得的資料量 | |
資料位置-相對位置 | offset | 10 | 識別已取得的資料位置 | 從 0 (0-based) 開始計數 |
資料位置-絕對位置 | max_id | 1 | 識別已取得的資料位置 | 使用唯一值,如員工 ID |
- 相對位置:適用儲存的資料量少,且新增與刪除頻率低。
https://api.example.com/v1/employees?limit=2&offset=1
- 絕對位置:適用儲存的資料量多,且新增與刪除頻率高。
http://192.168.0.200:3000/v1/employees?limit=2&max_id=1
參考資料:https://www.footmark.info/programming-language/design/restful-webapi-design-guide/
HTTP頭欄位 1
使用者代理 將 請求訊息 轉移至 Server,請求訊息 (request message) 範例:
GET /31/fetch-api HTTP/1.1 Host: notfalse.net User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:53.0) Gecko/20100101 Firefox/53.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8 Accept-encoding: gzip, deflate, br accept-language: zh-TW,zh;q=0.8,en-US;q=0.6,en;q=0.4 Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
- User-Agent:瀏覽器的瀏覽器身分標識字串
- Accept:能夠接受的回應內容類型(Content-Types)。
- Accept-Encoding:能夠接受的編碼方式列表。
- Authorization:用於超文字傳輸協定的認證的認證資訊
Cookie 2
- Cookie 是一種伺服器會傳送 HTTP 回應中的資料。 用戶端 (選擇性) 儲存在 cookie,然後將它傳回 subsequet 要求。 這可讓用戶端與伺服器共用狀態。
若要設定的 cookie,伺服器會納入回應 Set-cookie 標頭。 Cookie 的格式為名稱 / 值組,以選擇性屬性。
伺服器 HTTP 回應可以包含多個 Set-cookie 標頭和其他參數。
Set-Cookie: session-id=1234567; max-age=86400; domain=example.com; path=/;
- max-age:最大壽命,設定 cookie 的最長使用期限。 (優先使用)
- Expires: 設定 cookie 的到期日。
- path:將 cookie 限制為網域內指定的路徑
Web API 中的 cookie
將 cookie 加入至 HTTP 回應中,建立 CookieHeaderValue 執行個體,表示 cookie。 然後呼叫 AddCookies 擴充方法,其定義於 System.Net.Http。HttpResponseHeadersExtensions 類別,以新增 cookie。
public HttpResponseMessage Get() { var resp = new HttpResponseMessage(); var cookie = new CookieHeaderValue("session-id", "12345"); cookie.Expires = DateTimeOffset.Now.AddDays(1); cookie.Domain = Request.RequestUri.Host; cookie.Path = "/"; resp.Headers.AddCookies(new CookieHeaderValue[] { cookie }); return resp; }
若要從用戶端要求中擷取的 cookie,呼叫 GetCookies 方法:
string sessionId = ""; CookieHeaderValue cookie = Request.Headers.GetCookies("session-id").FirstOrDefault(); if (cookie != null) { sessionId = cookie["session-id"].Value; }