REST 全稱是 Representational State Transfer,有人說它是一種風格,並非一種標準,個人覺得挺有道理。它本身並沒有創造新的技術、元件與服務,更像是告訴大家如何更好地使用現有Web標準中的一些準則和約束,也不可否認,RESTFul 是目前最流行的 API 設計規範,用於 Web 資料介面的設計。
RESTful 風格的 API,在 HTTP 協議上使用的是標準 HTTP 方法,GET、PUT、POST 和 DELETE 等。
常用實踐
(1)API 返回結果通常為 JSON 形式,請求的頭部屬性 Accept 通常設定為 application/json
(2)請求的 Body 資料部分使用 JSON 形式
(3)鑑權資訊使用 JWT 等形式的授權碼方式,放在請求頭部屬性中傳輸,屬性名稱自定義,如 auth,token 等等
輔助類設計
(1)屬性定義
定義屬性:TokenHeaderName
上述實踐描述中,自定義部分為鑑權資訊在頭部屬性中的名稱,定義該屬性表示這個名稱。
定義屬性:DefaultToken
考慮到鑑權資訊在某些場景下可初始為一個固定值,定義該屬性在預設情況下使用。
具體定義如下:
// 鑑權 token 的請求頭屬性名稱
public String TokenHeaderName { get; set; }
// 預設的鑑權 token 資訊
public String DefaultToken { get; set; }
(2)方法定義
方法定義跟標準的 HTTP 方法一致,這裡定義常用的 Get、Put、Post、Delete 方法。
再抽取其中會重複的部分形成一些私有方法來複用,再過載一些方法使得可以應用預設引數值。
(2.1)構造方法
構造時可以指定鑑權頭部屬性名和 token,也可以不指定。
public RestApiVisitHelper()
{
}
// 構造時設定鑑權 token 的請求頭屬性名稱
public RestApiVisitHelper(String tokenHeaderName)
{
TokenHeaderName = tokenHeaderName;
}
// 構造時設定鑑權 token 的請求頭屬性名稱,以及預設的 token 值
public RestApiVisitHelper(String tokenHeaderName, String defaultToken){
TokenHeaderName = tokenHeaderName;
DefaultToken = defaultToken;
}
(2.2)訪問所需輔助方法
(2.2.1) 建立 WebClient,設定好相關屬性,包括鑑權頭部資訊
// 建立 WebClient 並設定好 token 資訊
private WebClient CreateWebClient(String token)
{
System.Net.ServicePointManager.ServerCertificateValidationCallback = ((sender, certificate, chain, sslPolicyErrors) => true);
System.Net.WebClient webClientObj = new System.Net.WebClient();
webClientObj.Headers.Add("Accept", "application/json");
if (!String.IsNullOrEmpty(TokenHeaderName) && !String.IsNullOrEmpty(token))
{
webClientObj.Headers.Add(TokenHeaderName, token);
}
webClientObj.Encoding = Encoding.UTF8;
return webClientObj;
}
(2.2.2)將查詢引數格式化拼接成最終 url
// 將查詢引數格式化拼接到 url 上形成最終的訪問地址
private String FormatUrl(String apiUrl, Hashtable queryParams)
{
String queryString = "";
foreach (var k in queryParams.Keys)
{
if (!String.IsNullOrEmpty(queryString))
{
queryString += "&";
}
queryString += String.Format("{0}={1}", k, queryParams[k]);
}
if (!String.IsNullOrEmpty(queryString))
{
apiUrl += "?" + queryString;
}
return apiUrl;
}
(2.2.3)異常統一處理
出現請求異常時,可以統一進行處理,具體返回結果可自行定義。
// 異常時返回的資訊:應該根據實際需要進行返回
private String WhenError(Exception e)
{
JObject result = new JObject();
result["err_code"] = -1;
if (e is WebException)
{
var we = (WebException)e;
if (we.Response != null) // 如果有輸出則仍然返回實際輸出
{
return new StreamReader(we.Response.GetResponseStream()).ReadToEnd();
}
else
{
result["err_msg"] = we.Message;
}
}
else
{
result["err_msg"] = e.Message;
}
return result.ToString(Newtonsoft.Json.Formatting.None);
}
(2.3)公開方法具體實現
有了以上輔助方法,實現程式碼會變得簡潔,且各個方法程式碼結構類似。以下以 Post 方法(包括過載) 為例展示基本實現。
/// <summary>
/// Post Api 返回結果文字,使用預設的鑑權 token
/// </summary>
/// <param name="apiUrl"></param>
/// <param name="queryParams"></param>
/// <param name="body"></param>
/// <returns></returns>
public String Post(string apiUrl, Hashtable queryParams, JObject body)
{
return Post(apiUrl, queryParams, body, DefaultToken);
}
/// <summary>
/// Post Api 返回結果文字
/// </summary>
/// <param name="apiUrl"></param>
/// <param name="queryParams"></param>
/// <param name="body"></param>
/// <param name="token"></param>
/// <returns></returns>
public String Post(string apiUrl, Hashtable queryParams, JObject body, String token)
{
System.Net.WebClient webClientObj = CreateWebClient(token);
apiUrl = FormatUrl(apiUrl, queryParams);
try
{
String result = webClientObj.UploadString(apiUrl, "POST", body.ToString(Newtonsoft.Json.Formatting.None));
return result;
}
catch (Exception ce)
{
return WhenError(ce);
}
}
完整原始碼
https://github.com/triplestudio/helloworld/blob/master/RestApiVisitHelper.cs