RESTful 設計
-
- RESTful
-
-
- 1. HTTP可見性
-
-
- 1. 1 GET
- 1.2 POST
- 1.3 PUT
-
- 2. 識别資源
-
-
- 2.1 業務實體指定資源
- 2.2 如何選擇資源粒度
- 2.3 将資源組織為集合
- 2.4 将資源合并為複合資源
-
- 3. HTTP實體頭
-
-
- 3.1 實體頭對應的表述
- 3.2 解釋實體頭
- 3.3 字元編碼不比對
- 3.4設計JSON類型
- 3.5 傳回分頁對象
-
-
- 注:
-
-
- 注1:Referer
-
基于《RESTful Web Service Cookbook》
RESTful
1. HTTP可見性
可見性是http的關鍵特性之一
-
衆所周知,http是通訊協定,那麼通訊的本質是什麼呢?
答:通訊其實是擷取消息(或者稱為資源,資料等等)的手段,相當于要能夠随時擷取(或者稱為看到)到其它程式(伺服器,代理,檢測軟體等)的消息,這就是可見性。
-
如何設計統一标準,使得可見性比較好呢?
答:一旦設計完成消息樣式,使用http提供的方法(如:get,post,本質是請求頭上的一種辨別符)來确定對消息的擷取方式(如:增删改查)
-
我們可以通過可見性實作哪些功能?
答:
- 可以實作消息的緩存(不修改資源就使用緩存,修改資源就重新整理緩存或使緩存失效)
- 樂觀鎖的并發控制(檢測修改消息的請求,控制并發)
- 選擇合适的消息表示方式
- 安全性和幂等性( 多次請求均與一次請求對消息的影響相同,可以確定重複請求不發生問題 )
保持可見性可以讓我們使用現有HTTP軟體的基礎設施來實作之前必須自己實作的功能
1. 1 GET
HTTP嚴重依賴GET方法的安全性和幂等性,用戶端希望能夠重複發起GET請求,而不必擔心造成副作用。
-
如何使用GET請求呢?
答:使用GET方法進行安全和幂等的消息的擷取(就是查詢消息,GET請求會被HTTP緩存)
1.2 POST
-
如何使用POST請求
答: HTTP不會緩存這一方法的響應,大部分HTTP工具不會自動重複送出POST請求
當我們需要 建立新的資源,執行需要大量資料輸入的查詢或通過控制器修改消息等情況下使用POST請求。
-
什麼時候看上去可以使用GET請求,其實應該使用POST請求?
答:如果是通過連結發起請求擷取資源時,HTTP協定會将目前頁面的URL作為Referer頭(注1)。這可能會把包含在URI中的敏感資訊洩露,這種情況要使用傳輸層安全協定(TLS)或者使用POST請求。
當查詢包含太多參數時,也應該使用POST。
1.3 PUT
我們可以使用POST或PUT建立新資源
-
什麼時候使用POST,什麼時候使用PUT?
答:隻有用戶端可以決定資源的URI時才使用PUT,否則使用POST。
就是伺服器已經對資源設定了添加的根目錄(例如:通過/user/{id}/{name}/home_address 路徑通路伺服器,伺服器對資源路徑指定了具體的使用者,這樣前端可以直接在URL上指定使用者建立家庭位址)
2. 識别資源
2.1 業務實體指定資源
可以直接将資料庫對象實體作為資源,可以通過GET,POST,PUT,DELETE進行CURD操作,但是對于其他類型接口,如:
- 生産随機數或機關轉換
- 擷取指定類型的使用者集合,列出前10個使用者
- 将錢從一個賬号轉到另一個賬戶
這些例子中,我們可以指定對于的名稱對應為資源,但是相應的操作沒辦法映射到GET,POST,PUT,DELETE這些HTTP方法中,需要額外的資源處理這些用例。
2.2 如何選擇資源粒度
-
選擇資源的标準是什麼?
答:可以通過網絡效率(緩存),響應内容大小及用戶端的易用程度來幫助确定資源的粒度
如:使用者可能包含位址,電話,賬号,好友關系等資訊,是将/user直接作為請求資源還是将/user/mobiles,/user/address等作為資源,這些最好從用戶端進行考慮。
2.3 将資源組織為集合
-
如何将一堆共用資源設計為一個資源來使用?
答: 對于共享同一資料的資源,有相同特性或屬性的資源或者用戶端看起來相似的資源封裝為同一資源,提供給用戶端。
如使用者資源可以分類為好友關系,親人關系,興趣關系等,這些關系可以看做同一資源,可以講URI設計為/user/{id}/friends和/user/{id}/interest/{interest_id}等
2.4 将資源合并為複合資源
-
如何提供一個又多條件組合而成的資源
答:從用戶端考慮,建立一些新的資源類,類聚合其他資源。
# 擷取使用者資料 GET /customer/123 HTTP/1.1 # 擷取最近10個購買訂單 GET /orders?customerid=123&sortby=date_desc&limit=10 HTTP/1.1 # 擷取最近10個待決定報價 GET /quotes?customerid=123&sortby=date_des&status=pending&$limit=10 HTTP/1.1
盡管這一系列GET請求能被伺服器接收,但它們太過頻繁,對用戶端而言,如果隻發送一條請求來擷取頁面所需的所有資料,可能效率更高一些。
針對同一使用者的多個資源,可以設計一個“使用者快照”,其中包含了所有資訊
# 請求 使用者快照 GET /customer/1234/snapshot HTTP/1.1 # 響應 包含了三個連結link和其對應的資料
3. HTTP實體頭
實體頭是HTTP請求頭及HTTP響應頭。
3.1 實體頭對應的表述
-
請求和響應中發送哪些HTTP頭?
答: 一下标記頭來描述消息正文
- Content-Type:描述消息類型,包含字元集或消息對應的類型參數
- Content-Length:消息大小
- Content-Language:消息本地化語言标記
- Content-MD5:進行消息一緻性校驗,TCP使用校驗和在傳輸層提供一緻性校驗
- Content-Encoding:使用gzip,compress或者deflate對消息進行壓縮編碼是,使用該标記頭
- Last-Modified:伺服器修改資源的最後修改時間
Content-Type:消息的類型,就是常說的media-type或者MIME,如text/html,image/png,application/xml,application/json和text/plain等,這些都是消息正文的編碼格式辨別符,就是資料傳輸過程中的類型,如xml或者json格式
3.2 解釋實體頭
-
如何解釋消息的實體頭和如何用實體頭來處理消息?
Content-Type:沒有該标簽,伺服器傳回400 (Bad Reqeust)
一定要基于Content-Type,Content-Language,Content-Encoding的值來确定響應的描述,不能根據用戶端發送了Accept:application/json或資源以.json結尾就确定響應格式是JSON。
3.3 字元編碼不比對
-
如何確定字元能被正确解釋
答:發送時帶上charset參數
3.4設計JSON類型
-
JSON類型的消息中要包含什麼資料
答:{
“link”:{
“rel”:“self”,
“href” :“http://www.example.org/person/1234”
}
}
3.5 傳回分頁對象
-
分頁對象的響應格式?
答: 包含 self:“目前連結”,prev:“上一頁連結”,next:“下一頁連結”,total:“總條數”
注:
注1:Referer
Referer是 HTTP請求
header
的一部分,當浏覽器(或者模拟浏覽器行為)向
web
伺服器發送請求的時候,頭資訊裡有包含 Referer。
表示從一個地方連結到目前網頁, 如超連結。
當我們通過百度搜尋後通路其他網站時(此時就是通過連結通路),Referer就指向百度URI。我們通過Referer來确定請求的通路來源(從哪個網站點進該請求的)。
如果直接在浏覽器位址欄輸入一個資源的URL位址,Referer為空