01 前言
回歸正題,看過很多RESTful相關的文章總結,參齊不齊,結合作業中的使用,非常有必要歸納一下關于RESTful架構方式了,RESTful只是一種架構方式的約束,給出一種約定的標準,完全嚴格遵守RESTful標準并不是很多,也沒有必要,但是在實際運用中,有RESTful標準可以參考,是十分有必要的,
實際上在作業中對api介面規范、命名規則、回傳值、授權驗證等進行一定的約束,一般的專案api只要易測驗、足夠安全、風格一致可讀性強、沒有歧義呼叫方便我覺得已經足夠了,介面是給開發人員看的,也不是給普通用戶去呼叫,
02 RESTful的來源
REST:Representational State Transfer(表象層狀態轉變),如果沒聽說過REST,你一定以為是rest這個單詞,剛開始我也是這樣認為的,后來發現是這三個單詞的縮寫,即使知道了這三個單詞理解起來仍然非常晦澀難懂,如何理解RESTful架構,最好的辦法就是深刻理解消化Representational State Transfer這三個單詞到底意味著什么,
1.每一個URI代表一種資源;
2.客戶端和服務器之間,傳遞這種資源的某種表現層;
3.客戶端通過四個HTTP動詞(get、post、put、delete),對服務器端資源進行操作,實作”表現層狀態轉化”,
是由美國計算機科學家Roy Fielding(百度百科沒有介紹,真是尷尬了),Adobe首席科學家、Http協議的首要作者之一、Apache專案聯合創始人,
03 RESTful6大原則
REST之父Roy Fielding在論文中闡述REST架構的6大原則,
1. C-S架構
資料的存盤在Server端,Client端只需使用就行,兩端徹底分離的好處使client端代碼的可移植性變強,Server端的拓展性變強,兩端單獨開發,互不干擾,
2. 無狀態
http請求本身就是無狀態的,基于C-S架構,客戶端的每一次請求帶有充分的資訊能夠讓服務端識別,請求所需的一些資訊都包含在URL的查詢引數、header、body,服務端能夠根據請求的各種引數,無需保存客戶端的狀態,將回應正確回傳給客戶端,無狀態的特征大大提高的服務端的健壯性和可拓展性,
當然這總無狀態性的約束也是有缺點的,客戶端的每一次請求都必須帶上相同重復的資訊確定自己的身份和狀態(這也是必須的),造成傳輸資料的冗余性,但這種確定對于性能和使用來說,幾乎是忽略不計的,
3.統一的介面
這個才是REST架構的核心,統一的介面對于RESTful服務非常重要,客戶端只需要關注實作介面就可以,介面的可讀性加強,使用人員方便呼叫,
4.一致的資料格式
服務端回傳的資料格式要么是XML,要么是Json(獲取資料),或者直接回傳狀態碼,有興趣的可以看看博客園的開放平臺的操作資料的api,post、put、patch都是回傳的一個狀態碼 ,
自我描述的資訊,每項資料應該是可以自我描述的,方便代碼去處理和決議其中的內容,比如通過HTTP回傳的資料里面有 [MIME type ]資訊,我們從MIME type里面可以知道資料的具體格式,是圖片,視頻還是JSON,客戶端通過body內容、查詢串引數、請求頭和URI(資源名稱)來傳送狀態,服務端通過body內容,回應碼和回應頭傳送狀態給客戶端,這項技術被稱為超媒體(或超文本鏈接),
除了上述內容外,HATEOS也意味著,必要的時候鏈接也可被包含在回傳的body(或頭部)中,以提供URI來檢索物件本身或關聯物件,下文將對此進行更詳細的闡述,
如請求一條微博資訊,服務端回應資訊應該包含這條微博相關的其他URL,客戶端可以進一步利用這些URL發起請求獲取感興趣的資訊,再如分頁可以從第一頁的回傳資料中獲取下一頁的URT也是基于這個原理,
4.系統分層
客戶端通常無法表明自己是直接還是間接與端服務器進行連接,分層時同樣要考慮安全策略,
5.可快取
在萬維網上,客戶端可以快取頁面的回應內容,因此回應都應隱式或顯式的定義為可快取的,若不可快取則要避免客戶端在多次請求后用舊資料或臟資料來回應,管理得當的快取會部分地或完全地除去客戶端和服務端之間的互動,進一步改善性能和延展性,
6.按需編碼、可定制代碼(可選)
服務端可選擇臨時給客戶端下發一些功能代碼讓客戶端來執行,從而定制和擴展客戶端的某些功能,比如服務端可以回傳一些 Javascript 代碼讓客戶端執行,去實作某些特定的功能,
提示:REST架構中的設計準則中,只有按需編碼為可選項,如果某個服務違反了其他任意一項準則,嚴格意思上不能稱之為RESTful風格,
03 RESTful的7個最佳實踐
1. 版本
如github開放平臺
https://developer.github.com/v3/
就是將版本放在url,簡潔明了,這個只有用了才知道,一般的專案加版本v1,v2,v3?好吧,這個加版本估計只有大公司大專案才會去使用,說出來不怕尷尬,我真沒用過,有的會將版本號放在header里面,但是不如url直接了當,
https://example.com/api/v1/
2.引數命名規范
query parameter可以采用駝峰命名法,也可以采用下劃線命名的方式,推薦采用下劃線命名的方式,據說后者比前者的識別度要高,可能是用的人多了吧,因人而異,因團隊規范而異吧,
https://example.com/api/users/today_login 獲取今天登陸的用戶
https://example.com/api/users/today_login&sort=login_desc 獲取今天登陸的用戶、登陸時間降序排列
3.url命名規范
API 命名應該采用約定俗成的方式,保持簡潔明了,在RESTful架構中,每個url代表一種資源所以url中不能有動詞,只能有名詞,并且名詞中也應該使用復數,實作者應使用相應的Http動詞GET、POST、PUT、PATCH、DELETE、HEAD來操作這些資源即可
不規范的的url,冗余沒有意義,形式不固定,不同的開發者還需要了解檔案才能呼叫,
https://example.com/api/getallUsers GET 獲取所有用戶
https://example.com/api/getuser/1 GET 獲取標識為1用戶資訊
https://example.com/api/user/delete/1 GET/POST 洗掉標識為1用戶資訊
https://example.com/api/updateUser/1 POST 更新標識為1用戶資訊
https://example.com/api/User/add POST 添加新的用戶
規范后的RESTful風格的url,形式固定,可讀性強,根據users名詞和http動詞就可以操作這些資源
https://example.com/api/users GET 獲取所有用戶資訊
https://example.com/api/users/1 GET 獲取標識為1用戶資訊
https://example.com/api/users/1 DELETE 洗掉標識為1用戶資訊
https://example.com/api/users/1 Patch 更新標識為1用戶部分資訊,包含在body中
https://example.com/api/users POST 添加新的用戶
4. 統一回傳資料格式
對于合法的請求應該統一回傳資料格式,這里演示的是json
- code——包含一個整數型別的HTTP回應狀態碼,
- status——包含文本:”success”,”fail”或”error”,HTTP狀態回應碼在500-599之間為”fail”,在400-499之間為”error”,其它均為”success”(例如:回應狀態碼為1XX、2XX和3XX),這個根據實際情況其實是可要可不要的,
- message——當狀態值為”fail”和”error”時有效,用于顯示錯誤資訊,參照國際化(il8n)標準,它可以包含資訊號或者編碼,可以只包含其中一個,或者同時包含并用分隔符隔開,
- data——包含回應的body,當狀態值為”fail”或”error”時,data僅包含錯誤原因或例外名稱、或者null也是可以的
回傳成功的回應json格式
{
"code": 200,
"message": "success",
"data": {
"userName": "123456",
"age": 16,
"address": "beijing"
}
}
回傳失敗的回應json格式
{
"code": 401,
"message": "error message",
"data": null
}
下面這個ApiResult的泛型類是在專案中用到的,拓展性強,使用方便,回傳值使用統一的 ApiResult 或 ApiResult
錯誤回傳 使用 ApiResult.Error 進行回傳; 成功回傳,要求使用 ApiResult.Ok 進行回傳
public class ApiResult: ApiResult
{
public new static ApiResult<T> Error(string message)
{
return new ApiResult<T>
{
Code = 1,
Message = message,
};
}
[JsonProperty("data")]
public T Data { get; set; }
}
public class ApiResult
{
public static ApiResult Error(string message)
{
return new ApiResult
{
Code = 1,
Message = message,
};
}
public static ApiResult<T> Ok<T>(T data)
{
return new ApiResult<T>()
{
Code = 0,
Message = "",
Data = https://www.cnblogs.com/IT-Evan/p/data
};
}
/// <summary>
/// 0 是 正常 1 是有錯誤
/// </summary>
[JsonProperty("code")]
public int Code { get; set; }
[JsonProperty("msg")]
public string Message { get; set; }
[JsonIgnore]
public bool IsSuccess => Code == 0;
}
5. http狀態碼
在之前開發的xamarin android博客園客戶端的時候,patch、delete、post操作時body回應里面沒有任何資訊,僅僅只有http status code,HTTP狀態碼本身就有足夠的含義,根據http status code就可以知道洗掉、添加、修改等是否成功,(ps:有點linux設計的味道哦,沒有回傳訊息就是最好的訊息,表示已經成功了)服務段向用戶回傳這些狀態碼并不是一個強制性的約束,簡單點說你可以指定這些狀態,但是不是強制的,常用HTTP狀態碼對照表
HTTP狀態碼也是有規律的
- 1**請求未成功
- 2**請求成功、表示成功處理了請求的狀態代碼,
- 3**請求被重定向、表示要完成請求,需要進一步操作, 通常,這些狀態代碼用來重定向,
- 4** 請求錯誤這些狀態代碼表示請求可能出錯,妨礙了服務器的處理,
-
5**(服務器錯誤)這些狀態代碼表示服務器在嘗試處理請求時發生內部錯誤, 這些錯誤可能是服務器本身的錯誤,而不是請求出錯,
6. 合理使用query parameter
在請求資料時,客戶端經常會對資料進行過濾和分頁等要求,而這些引數推薦采用HTTP Query Parameter的方式實作
比如設計一個最近登陸的所有用戶
https://example.com/api/users?recently_login_day=3
搜索用戶,并按照注冊時間降序
https://example.com/api/users?recently_login_day=3
搜索用戶,并按照注冊時間升序、活躍度降序
https://example.com/api/users?q=key&sort=create_title_asc,liveness_desc
關于分頁,看看博客園開放平臺分頁獲取精華區博文串列
https://api.cnblogs.com/api/blogposts/@picked?pageIndex={pageIndex}&pageSize={pageSize}
回傳示例:
[
{
“Id”: 1,
“Title”: “sample string 2”,
“Url”: “sample string 3”,
“Description”: “sample string 4”,
“Author”: “sample string 5”,
“BlogApp”: “sample string 6”,
“Avatar”: “sample string 7”,
“PostDate”: “2017-06-25T20:13:38.892135+08:00”,
“ViewCount”: 9,
“CommentCount”: 10,
“DiggCount”: 11
},
{
“Id”: 1,
“Title”: “sample string 2”,
“Url”: “sample string 3”,
“Description”: “sample string 4”,
“Author”: “sample string 5”,
“BlogApp”: “sample string 6”,
“Avatar”: “sample string 7”,
“PostDate”: “2017-06-25T20:13:38.892135+08:00”,
“ViewCount”: 9,
“CommentCount”: 10,
“DiggCount”: 11
}
]
7. 多表、多引數連接查詢如何設計URL
這是一個比較頭痛的問題,在做單個物體的查詢比較容易和規范操作,但是在實際的API并不是這么簡單而已,這其中常常會設計到多表連接、多條件篩選、排序等,
比如我想查詢一個獲取在6月份的訂單中大于500元的且用戶地址是北京,用戶年齡在22歲到40歲、購買金額降序排列的訂單串列
https://example.com/api/orders?order_month=6&order_amount_greater=500&address_city=北京&sort=order_amount_desc&age_min=22&age_max=40
從這個URL上看,引數眾多、呼叫起來還得一個一個仔細對著,而且API本身非常不容易維護,命名看起來不是很容易,不能太長,也不能太隨意,
在.net WebAPI總我們可以使用屬性路由,屬性路由就是講路由附加到特定的控制器或操作方法上裝飾Controll及其使用[Route]屬性定義路由的方法稱為屬性路由,
這種好處就是可以精準地控制URL,而不是基于約定的路由,簡直就是為這種多表查詢量身定制似的的, 從webapi 2開發,現在是RESTful API開發中最推薦的路由型別,
我們可以在Controll中標記Route
[Route(“api/orders/{address}/{month}”)]
Action中的查詢引數就只有金額、排序、年齡,減少了查詢引數、API的可讀性和可維護行增強了,
https://example.com/api/orders/beijing/6?order_amount_greater=500&sort=order_amount_desc&age_min=22&age_max=40
這種屬性路由比如在博客園開放的API也有這方面的應用,如獲取個人博客隨筆串列
請求方式:GET
請求地址:https://api.cnblogs.com/api/blogs/{blogApp}/posts?pageIndex={pageIndex}
(ps:blogApp:博客名)
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/102213.html
標籤:其他
上一篇:網站如何被百度快速收錄呢?
下一篇:docker 鏡像管理
