在網際網路發展過程中,最開始是以html靜態網頁展示內容,url的表現形式一般為 http://www.example.com/getInfo.html;後來隨著需求不斷提高以及為了應對這種需求,出現了動態網頁技術,在動態網頁技術中http請求的url形式一般為 http://www.example.com/getInfo.java?id=1&name=tom ,或者是重寫後的url形式http://www.example.com/getInfo/id/1/name/tom 等這種形式。其實這種url的形式是不是有點RESTful的樣子了,但是當時還沒有這種思想。
在2000年的時候,Roy Thomas Fielding博士在他的博士論文中提出了一種全球資訊網的軟體架構風格-REST(全稱:Representational State Transfer, 表現層狀態轉換),目的是便於在不同軟體/程序中(例如網際網路)中互相傳遞信息。這種表現層狀態轉換是基於HTTP協議之上而確定的一組約束和屬性,是一種設計提供全球資訊網服務的軟體架構風格。
題外話:他也是HTTP協議(1.0版和1.1版)的主要起草者之一、 Apache伺服器軟體的作者之一、Apache基金會的第一任主席。
符合或兼容於這種架構風格(簡稱為 REST 或 RESTful)的網絡服務,允許客戶端發出以統一資源標識符訪問和操作網絡資源的請求,而與預先定義好的無狀態操作集一致化。因此表現層狀態轉換提供了在網際網路的計算系統之間,彼此資源可交互使用的協作性質。(維基百科)
二:怎麼理解RESTful上面的說明比較學術,其實我抓住幾個重點詞彙:網絡資源,資源標識符號,無狀態,表現層,狀態轉換。
網絡資源:就是我們需要獲取的數據,比如媒體,文本,圖片,視頻等等都可以看作是一種資源。
表現層:「資源」是一種信息實體,它可以有多種外在表現形式,比如上面網絡資源說明。我們把「資源」具體呈現出來的形式,叫做它的「表現層(Representation)」
資源標識符號:定位資源用的。就像門牌號碼可以定位到具體的房間。怎麼定位到你需要的資源?就需要用一個資源標識符-URI(統一資源定位符)。每種資源對應一個特定的URI。要獲取資源,訪問URI就可以,URI是每一個資源的獨一無二的地址。就像在網絡世界中,IP位址可以定位到獨一無二的一臺伺服器一樣。
無狀態:我們訪問網站時,就是客戶端和服務端的一次交互,這就涉及到數據和狀態的變化。無狀態就是每次訪問時,服務端不會保留客戶端的信息,每一次客戶端訪問服務端都是一次全新的訪問。HTTP協議就是一種無狀態協議。
狀態轉換:HTTP協議是一個無狀態的協議,意思是說所有的狀態都是保存在服務端。那麼客戶端要操作服務端,必須要通過某種手段,讓服務端發生「狀態轉換」(State Transfer)。而這種轉換是建立在表現層之上的,就是「表現層狀態轉換」。
HTTP協議是怎麼做到的?就是通過HTTP協議的方法METHOD來操作:GET、PUT、DELETE、POST、PATCH。它們分別對應的四種基本操作時:GET用來獲取資源,POST用來新建資源(也可以用於更新資源),PUT用來更新資源,DELETE用來刪除資源,PATCH用來更新部分資源。
有一種資源,每種資源有唯一的URI來標識。
對這種資源進行操作,實現狀態轉換。通常用HTTP的方法來操作。
誰來操作誰呢?客戶端對服務度資源的操作
具備上面的這幾種要素,就是RESTful架構。RESTful是一種設計風格。
四:RESTful API實踐API設計RESTful API 是基於REST架構設計理念之下利用http協議來描述接口操作接口。
這種API設計主要描述幾個部分:
URL的設計,URL裡面當然包含了資源定位符。
Request參數
Response 返回數據
URL Request一個URL設計,需要簡單,易懂,看到URL就能知道這個URL的意思,也就是自解釋,自描述。
看看http url的設計,分為協議,域名,path,method,參數。
我們應該可以得到啟發,它其實就是根據http協議而來。
比如獲取僱員url:GET /users, 動作方法+path
比如 GET 操作:
GET http://example.com/users 獲取所有的員工信息
GET http://example.com/users/23 獲取員工id=23的信息
方法/資源http://example.com/usershttp://example.com/users/23GET獲取所有的用戶信息獲取用戶id為23的信息POST在所有用戶信息中創建/追加一個新的用戶在id=23號用戶新增信息PUT更新該組用戶信息更新id=23號的用戶信息DELETE刪除所有的用戶信息刪除id=23號用戶信息PATCH更新所有用戶部分信息更新id=23號用戶信息常見錯誤:
比如新建一個用戶:POST http://example.com/users/22 ,這種形式是錯誤的,應該用
POST http://example.com/users
上面的 example.com/users,users複數形式,而且是名詞。因為常見的操作是一個集合。所以一般建議用複數形式。不推薦使用 example.com/user/1這種形式,而是推薦使用example.com/users/1 複數這種形式。
錯誤的表示形式:
GET http://example.com/getusers - 不要使用這種帶有get動詞的形式
getusers 前面帶一個get是多餘的,因為http請求的動作就是GET,不用寫多餘的動作了。如果這樣寫的話,很容易造成大家理解api不統一。有可能前端和後端人員各自為政,用不同的動詞來操作url,造成大家開發理解的不統一。
類似的還有:
/createUsers
/updateUserInfo
/deleteUser?id=2
統一標準:前後端人員統一用http規定的幾個動作來進行url相關的操作。不需要在url後面加多餘的動作名詞。統一用一個標準,這樣前後端人員理解起來也能統一思想,便於大家協作開發。
在操作資源的時候,最簡單的操作是CURD,但是資源之間相互關聯也很常見,資源嵌套也很常見,比如查找id為10的用戶所有文章,這個URL如何設計?
一種設計:
GET /users/10/articles
獲取article的id=3文章
GET /users/10/articles/3
有人推薦這種方案,這種形式的 URI 一定程度上描述了 user 與 article 之間的一對多關係,但同時,我們就不太能夠分清當前端點返回的數據到底是 user 類型還是 article 類型。
這種設計語義不明確,也不利於擴展。
另一種設計,除了第一級,其他級別都用查詢字符串表達:
GET /articles?user_id=10
推薦使用這種方案。
比如用戶發布文章:GET /atticles?user_id=10&published=true
比如我們用獨立的api域名:api.example.com。
或者在域名後面加 api,這種形式 example.com/api/users 。
這樣有利於以後我們遷移,擴展。
是否在URL中加入版本號,有一個爭論。
有的認為不要在URL中加入版本號,可以在請求頭信息中加入。因為不同的版本,可以理解成同一種資源的不同表現形式,所以應該採用同一個URI。
Accept: application/example.com+json; version=3
有的則認為在URL中放入版本號,操作簡單。在api變更時候,更容易操作些:
GET api.example.com/v1/users
根據個人來選擇,一般推薦在url中寫上版本號。
篩選過濾複雜參數-複雜業務場景對可選的、複雜的參數,使用查詢字符串querystring(?)
比如說有一些複雜的業務場景,比如對獲取的資源在進行條件篩選,還有排序,分頁等等
對於這些場景,RESTful api又怎麼設計?用querystring
比如某一個用戶已經發表的文章:
GET /users/10/posts?state=published
GET /users/10/posts?published=true
比如用戶分頁:
GET /users?page=1&page_size=10
在加條件,某一個用戶已經發表的文章太多,需要分頁:
GET /users/10/posts?published=true&page=2&page_size=10
針對多個欄位,不同的排序:
搜索用戶,並按照註冊時間升序、活躍度降序
GET /users?q=key&sort=create_time_asc,liveness_desc
GET /users?fields=id,title,desc;
github的搜索某一用戶分頁排序的api:
https://api.github.com/search/users?q={query}{&page,per_page,sort,order}"
查詢的條件q,如果有需要還有分頁page,per_page,排序sort,order。
github某個用戶的repo,類型,分頁,排序
https://api.github.com/users/{user}/repos{?type,page,per_page,sort}",
github的api查看地址:https://api.github.com/
一些非資源的特殊請求有時API調用並不涉及資源(如計算,翻譯或轉換)。例:
GET /translate?from=de_DE&to=en_US&text=Hallo
GET /calculate?para2=23¶2=432
在這種情況下,API響應不會返回任何資源。而是執行一個操作並將結果返回給客戶端。因此,您應該在URL中使用動詞而不是名詞,來清楚的區分資源請求和非資源請求。
返回格式和狀態碼統一比如返回一個統一json格式:
Copy
{1xx:相關信息
2xx:操作成功
3xx:重定向
4xx:客戶端錯誤
5xx:伺服器錯誤
200 表示操作成功,但是不同的方法可以返回更精確的狀態碼
GET: 200 OK
POST: 201 Created
PUT: 200 OK
PATCH: 200 OK
DELETE: 204 No Content
使用狀態碼 202 有時候會比 使用狀態啊嗎 201 是更好的選擇,狀態碼 202 的意思是:服務端已接收到了請求,但是還沒有創建任何資源,但結果一切正常
我分享兩種特別適合使用 202 Accepted 狀態碼的業務場景:
3xx 狀態碼重定向,需要進一步的操作以完成請求
301 Moved Permanently:永久移動。請求的資源已被永久的移動到新URI,返回信息會包括新的URI,瀏覽器會自動定向到新URI。今後任何新的請求都應使用新的URI代替
302 Found:已找到。請求的資源已經在其他臨時位置找到,並應該在響應頭中返回該位置。只有GET和HEAD請求應該重定向到該位置。
304 Not Modified:未修改。所請求的資源未修改,伺服器返回此狀態碼時,不會返回任何資源。客戶端通常會緩存訪問過的資源,通過提供一個頭信息指出客戶端希望只返回在指定日期之後修改的資源
4xx 狀態碼表示客戶端的錯誤,主要有以下幾種:
400 Bad Request:伺服器不理解客戶端的請求,未做任何處理
401 Unauthorized:用戶未提供身份驗證憑據,或者沒有通過身份驗證
403 Forbidden:用戶通過了身份驗證,但是不具有訪問資源所需的權限
404 Not Found:所請求的資源不存在,或不可用
405 Method Not Allowed:該http方法不被允許。
406 Not Acceptable :GET, 用戶請求的格式不可得(比如用戶請求JSON格式,但是只有XML格式)。
410 gone : 這個url對應的資源現在不可用。
415 Unsupported Media Type:客戶端要求的返回格式不支持。比如,API 只能返回 JSON 格式,但是客戶端要求返回 XML 格式
429 Too Many Requests : 請求太多 -由於速率限制而拒絕請求時
5xx 狀態碼表示服務端錯誤
500 Internal Server Error:客戶端請求有效,伺服器處理時發生了意外
502 Bad Gateway:作為網關或者代理工作的伺服器嘗試執行請求時,從上遊伺服器接收到無效的響應
503 Service Unavailable:伺服器無法處理請求,一般用於網站維護狀態
505 HTTP Version Not Supported: 伺服器不支持,或者拒絕支持在請求中使用的HTTP版本
RESTful API最好做到Hypermedia,即返回結果中提供連結,連向其他API方法,使得用戶不查文檔,也知道下一步應該做什麼。比如,當用戶向api.example.com的根目錄發出請求,會得到這樣一個文檔。
{
"link": {
"rel": "collection https://www.example.com/users",
"href": "https://api.example.com/users",
"title": "List of users",
"type": "application/vnd.yourformat+json"
}
}
上面代碼表示,文檔中有一個link屬性,用戶讀取這個屬性就知道下一步該調用什麼API了。rel表示這個API與當前網址的關係(collection關係,並給出該collection的網址),href表示API的路徑,title表示API的標題,type表示返回類型。
Hypermedia API的設計被稱為HATEOAS。Github的API就是這種設計,訪問api.github.com會得到一個所有可用API的網址列表。
// https://api.github.com/
{
"current_user_url": "https://api.github.com/user",
"current_user_authorizations_html_url": "https://github.com/settings/connections/applications{/client_id}",
"authorizations_url": "https://api.github.com/authorizations",
"code_search_url": "https://api.github.com/search/code?q={query}{&page,per_page,sort,order}",
"commit_search_url": "https://api.github.com/search/commits?q={query}{&page,per_page,sort,order}",
"emails_url": "https://api.github.com/user/emails",
"emojis_url": "https://api.github.com/emojis",
... ...
}
想獲取當前用戶信息,訪問 https://api.github.com/user,會返回
// https://api.github.com/user
{
"message": "Requires authentication",
"documentation_url": "https://developer.github.com/v3/users/#get-the-authenticated-user"
}
上面代碼表示,伺服器給出了提示信息,以及文檔的網址。
上面介紹的,其實是martin fowler 劃分RESTful api4個等級最高的一個等級:
他畫的api 4個等級圖:
(from: https://martinfowler.com/articles/richardsonMaturityModel.html)
使用 / 來表示資源層級關係
使用 ? 來過濾資源
使用 , 或 ; 來表示資源同級層關係
使用 _ 或 - 來表示更友好的URL形式
一些設計也可以參考github的v3: https://developer.github.com/v3/
或者一些其他大廠twitter, https://developer.twitter.com/en,
google等等
https://zh.wikipedia.org/wiki/REST
http://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm
http://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm
https://www.ruanyifeng.com/blog/2018/10/restful-api-best-practices.html
https://www.ruanyifeng.com/blog/2011/09/restful.html
https://blog.florimondmanca.com/restful-api-design-13-best-practices-to-make-your-users-happy
https://martinfowler.com/articles/richardsonMaturityModel.html
https://zh.wikipedia.org/wiki/HTTP狀態碼
https://www.w3.org/Protocols/rfc2616/rfc2616.html
·END·
如果您喜歡本文,歡迎點擊右上角,把文章分享到朋友圈~~
作者:九卷
來源:www.cnblogs.com/jiujuan/p/12791574.html
版權申明:內容來源網絡,版權歸原創者所有。除非無法確認,我們都會標明作者及出處,如有侵權煩請告知,我們會立即刪除並表示歉意。謝謝!
我們都是架構師!
關注架構師(JiaGouX),添加「星標」
獲取每天技術乾貨,一起成為牛逼架構師
技術群請加若飛:1321113940 進架構師群
投稿、合作、版權等郵箱:admin@137x.com