深刻理解 RESTful Api 架構

一些常見的誤解

不要覺得 RESTful Api  就是設計得像便於 SEO 的僞靜態,例如一個 Api 的 URL 相似於 http://xxx.com/blog/1 ,咱們能夠經過瀏覽器訪問該 URL 而讀取文章,可是這並不表明着它就是 RESTful Api 。html

也不要認爲URL 裏有 queryString 就不是 RESTful Api ,例如 http://xxx.com/users/?page=10&page_size=30git

更不要認爲 HTTP + JSON 就是 RESTful ApI 了。github

REST 和 HTTP/1.1 

Roy Fielding (Apache HTTP 服務器的核心開發者,Apache 軟件基金會的合做創始人,HTTP/1.1 協議專家組的負責人)總結了一套理論框架,而後使用這套理論框架中的指導原則,來指導HTTP/1.1協議的設計方向。後來他在其的博士學位論文 Architectural Styles and the Design of Network-based Software Architectures 中更爲系統、嚴謹地闡述了這套理論框架,而且使用這套理論框架推導出了一種新的架構風格,而且爲這種架構風格取了一個使人輕鬆愉快的名字 REST。api

想必經過這個你已經明白了 REST 和 HTTP/1.1 的密不可分的關係了吧。HTTP/1.1 的不少特性就是 REST 的特性,好比鏈接的無狀態性。還有後面說的 REST 五大特性都和 HTTP/1.1 協議密不可分。瀏覽器

RESTful Api 與 SOAP Web API 在 URL 形式上的對比

從設計一個刪除評論的 api 提及 

咱們能夠這樣設計成相似於:緩存

http://mengkang.net/?method=comment.del&id=x 服務器

http://mengkang.net/comment/del/id/x restful

或者其餘形式的 url。markdown

而 RESTful Api 則是:網絡

[DELETE] http://mengkang.net/comments/1 

 

咱們對比能夠發現①和② URL 中,都有del的動做指示。

SOAP Web API採用RPC風格,它採用面向功能的架構,因此咱們在設計SOAP Web API的時候首相考慮的是應高提供怎樣的功能(或者操做)。

而 RESTful Api 是面向資源的架構。是查詢、新增、修改、刪除,都該資源無關。

因此咱們在③ URL 中沒有看到del的關鍵字,對比②和③最爲明顯。

進一步認識 RESTful Api 

咱們知道 URL 全稱爲「統一資源定位符(Uniform Resource Locator)」,用於描述 Web 資源所在的位置。RESTful Api 是以 HTTP 協議爲強烈依託的,將相似於①和②這種以功能爲主導的URL風格捨棄,還原 URL 的本質,它的宗旨就是一個 URL 就應該是一個資源,不能包含任何動做。

[POST]     http://mengkang.net/users   // 新增
[GET]      http://mengkang.net/users/1 // 查詢
[PATCH]    http://mengkang.net/users/1 // 更新
[PUT]      http://mengkang.net/users/1 // 覆蓋,所有更新
[DELETE]   http://mengkang.net/users/1 // 刪除

 

 

PUTPATCH的功能均可以表明更新,但略有不一樣,PUT大多時候表示更新該資源的所有信息,而PATCH則更新部分信息。 

PUTPOST又一些功能的重疊,均可以是新建一個資源,POST時,新建資源的地址是由服務器返回給客戶端的。也就是說客戶端在發送POST請求資源以前還沒法預知該資源的地址,這在咱們的 Api 開發中很是常見,新建一個帖子,新建一條評論,都如此。

而資源的地址是客戶端預先知道的狀況則比較少。也有人如此設計而使用PUT,好比須要對 github 上的某人的項目 star ,則可能會設計成:http://github.com/xxx/zhoumengkang/projectname/star 這裏把「對這個項目已經點贊過」當作了一個資源,那麼就能夠用PUT,由於要刪除這個資源時,仍是訪問這個 URL。

關於這些功能上有交集的地方,可能後面會有一些更加標準的規範或者協議吧。

最後說下HEADOPTIONSHEAD請求的是資源的元數據,好比一張照片,的元數據則可能包含了,照片拍攝的設備,地點,時間等。服務器通常將對應資源的元數據置於響應的報頭集合返回給客戶端,這樣的響應通常不具備主體部分。OPTIONS則是發送一種「探測」請求以肯定針對某個目標地址的請求必須具備怎樣的約束(好比應該採用怎樣的HTTP方法以及自定義的請求報頭),而後根據其約束髮送真正的請求。

關於過濾篩選,排序和 token 等 query string 是支持使用,和惟一資源的概念並不衝突。

我所理解的無狀態性和惟一資源對 Api Url 的設計指導

舉一個實際的例子,用戶黑名單的 CURD。咱們但是設計成

 

 

[GET]      /blacklist
[PUT]       /blacklist/{id} #把 id 加入到當前受權用戶的黑名單中
[DELETE]   /blacklist/{id}

 

REST的五大特性如上的 api 設計中,首先如上的 url 設計中,經過受權碼中獲取登陸用戶 uid。則是有狀態的了,其次由於全部的用戶訪問的資源都是同一個地址,這與惟一資源的概念是相違背的。若是是無狀態的,那麼就與惟一資源的概念相吻合了。(這只是 restful 所建議的,實際是否須要徹底遵照視狀況而定)

  1. 資源(Resource)

  2. 資源的表述(Representation)

  3. 狀態轉移(State Transfer)

  4. 統一接口(Uniform Interface)

  5. 超文本驅動(Hypertext Driven)

資源的概念是 RESTful 裏面最重要的一個概念,很容易被咱們忽視和誤解,因此就重點闡述了這一特性。

而其餘特性,咱們平常開發應該都是遵照的,就再也不展開說了,須要瞭解的能夠看個人這篇筆記 REST的五個特性 。

Server 端代碼的基本設計思想

按照 RESTful Api 的規範,嚴格來講根據endpoint找到在 server 端映射成一個資源對象,例如經過 http://mengkang.net/users/1 找到UserResource對象

而在這個對象裏對應着該資源支持的 Http 協議的方法。若是一個對象支持7種方式的請求,則相似於:

複製代碼
public class UserResource {
 
    private User user;
 
    public UserResource() {
 
    }
 
    public UserResource(int id) {
        //從數據查詢處該用戶的數據
        String name = "xxx";
        short age = 23;
        user = new User(id,name,age);
    }
 
    /**
     * 獲取單個用戶
     * 從 new UserResource(int) 開始
     * @return
     */
    public User get(){
        return user;
    }
 
    /**
     * 覆蓋用戶的所有信息
     * 從 new UserResource(int) 開始
     * @return
     */
    public boolean put(){
        return true;
    }
 
    /**
     * 只更新用戶的部分信息
     * 從 new UserResource(int) 開始
     * @return
     */
    public boolean patch(){
        return true;
    }
 
    /**
     * 建立一個 UserResource
     * @return
     */
    public int post(){
        return 1;
    }
 
    /**
     * 刪除用戶
     * @return
     */
    public boolean delete(){
        return true;
    }
 
}
複製代碼

 

假如咱們規定 URL 爲 http://mengkang.net/user/1/star 表示是訪問者對 id 爲 1 的這個用戶的 star 狀態的一個資源。(當前訪問者的信息經過 query string 傳遞 auth token 的形式獲取)若是有關注的 api 那麼對於該用戶的 star 操做則應新建一個UserStarResource資源對象,由於每一個資源最多隻有這7中方法,構造方法除外,而不能有其餘的相關的動做方法。

複製代碼
public class UserStarResource {
 
    public boolean get(){
        return true;
    }
 
    public boolean post(){
        return true;
    }
    public boolean delete(){
        return true;
    }
}
複製代碼

 

REST 狀態碼

理論上來講咱們應該以 Http response status code 做爲客戶端的標準,而不是在 Http body 體裏面定義。這樣客戶端的可以更快速的獲取服務端的響應狀態碼。

可是因爲國內某些網絡商會劫持狀態碼非200的請求,跳轉到他們的廣告地址。因此你們仍是考慮國內的實際狀況。

REST 架構風格約束

  1. 客戶-服務器(Client-Server)通訊只能由客戶端單方面發起,表現爲請求-響應的形式。

  2. 無狀態(Stateless)通訊的會話狀態(Session State)應該所有由客戶端負責維護。

  3. 緩存(Cache)響應內容能夠在通訊鏈的某處被緩存,以改善網絡效率。

  4. 統一接口(Uniform Interface)通訊鏈的組件之間經過統一的接口相互通訊,以提升交互的可見性。

  5. 分層系統(Layered System)經過限制組件的行爲(即,每一個組件只能「看到」與其交互的緊鄰層),將架構分解爲若干等級的層。

文字比較學院派,仔細一想,想必也發現咱們實際工做都已經遵照這五條架構風格了。

相關文章
相關標籤/搜索