- REST實際上是一種組織Web服務的架構,而並非咱們想象的那樣是實現Web服務的一種新的技術,更沒有要求必定要使用HTTP。其目標是爲了建立具備良好擴展性的分佈式系統。
- 做爲一種架構,其提出了一系列架構級約束。這些約束有:
- 使用客戶/服務器模型。客戶和服務器之間經過一個統一的接口來互相通信。
- 層次化的系統。在一個REST系統中,客戶端並不會固定地與一個服務器打交道。
- 無狀態。在一個REST系統中,服務端並不會保存有關客戶的任何狀態。也就是說,客戶端自身負責用戶狀態的維持,並在每次發送請求時都須要提供足夠的信息。
- 可緩存。REST系統須要可以恰當地緩存請求,以儘可能減小服務端和客戶端之間的信息傳輸,以提升性能。
- 統一的接口。一個REST系統須要使用一個統一的接口來完成子系統之間以及服務與用戶之間的交互。這使得REST系統中的各個子系統能夠獨自完成演化。
若是一個系統知足了上面所列出的五條約束,那麼該系統就被稱爲是RESTful的。api
- 無狀態約束在其它類型的Web服務中並不十分常見,所以如何避免違反該約束是在實現REST服務時最常討論的話題。其不只僅會影響到不少功能的設計,更是REST系統擴展性的關鍵。
- 資源是REST系統的核心概念。全部的設計都會以資源爲中心,包括如何對資源進行添加,更新,查找以及修改等。而資源自己則擁有一系列狀態。在每次對資源進行添加 ,刪除或修改的時候,資源就將從一個狀態轉移到另一個狀態。
-
統一接口這個約束包含了四個子約束:緩存
- 每一個資源都擁有一個資源標識。每一個資源的資源標識能夠用來惟一地標明該資源。
- 消息的自描述性。在REST系統中所傳遞的消息須要可以提供自身如何被處理的足夠信息。例如該消息所使用的MIME類型,是否能夠被緩存等。(消息格式)
- 資源的自描述性。一個REST系統所返回的資源須要可以描述自身,並提供足夠的用於操做該資源的信息,如如何對資源進行添加,刪除以及修改等操做。也就是說,一個典型的REST服務不須要額外的文檔對如何操做資源進行說明。屬性都清晰地描述了自身所表達的含義。(屬性都清晰地描述了自身所表達的含義,例如:經過brands屬性表示了該分類中的著名品牌,並經過hot_searches標示了在該分類中的熱搜關鍵字)
- HATEOAS。即客戶只能夠經過服務端所返回各結果中所包含的信息來獲得下一步操做所須要的信息,如究竟是向哪一個URL發送請求等。也就是說,一個典型的REST服務不須要額外的文檔標示經過哪些URL訪問特定類型的資源,而是經過服務端返回的響應來標示到底能在該資源上執行什麼樣的操做。一個REST服務的客戶端也不須要知道任何有關哪裏有什麼樣的資源這種信息。
- 發送GET /api ,返回的響應中將標示出REST API的版本以及全部能夠訪問的資源等信息。
- 資源的狀態轉移:在一個REST系統中,購物車將被抽象爲一個資源,而「將商品放入購物車」這個操做將被解釋爲對購物車這個資源的更新:更新購物車,以使特定商品包含在購物車內。
- 咱們對某個操做不要再關注它所執行的動做,而是關心它所操做的賓語。一般狀況下,該賓語就會是REST系統中的資源。
- 可是有時候,一個動做可能並不存在着它所操做的賓語。在這種狀況下,咱們就須要考慮該動做產生或消除了哪一個實體,或者哪一個實體的狀態發生了變化。這個發生了變化的實體實際上就是一種資源。例如對於登錄這一行爲,其實際上在服務端建立了一個會話實例。該會話實例中則包含了登錄IP,登錄時間,以及登錄時所用的憑證等。再好比對於用戶更改密碼這種行爲,其所操做的資源就是用戶資料。
-
那麼如何判斷咱們爲REST服務所定義的資源是否合理呢?通常狀況下,我都使用下面的一些判斷方法:服務器
首先,咱們須要考慮對該資源的CRUD是否有意義,從而驗證資源的定義是否合理。就以剛剛說到的列表的分頁顯示爲例,咱們能夠想象一下如何對分頁進行添加和刪除?一旦刪除了該分頁,那麼屬於該分頁中的各個商品也應該被刪除麼?並且刪除了分頁X的數據後,本來X + 1分頁的數據將展現在X分頁中。很顯然,將商品的分頁定義爲資源並不合理。架構
其次,咱們須要檢查資源是否須要除CRUD以外的動詞來操做。該方法用來檢查資源中是否還有子資源沒有被抽象。若是該資源還須要額外的動詞,那麼咱們就須要考慮這些操做到底引發了什麼樣的狀態變化,進而抽象出該資源的子資源。分佈式
除此以外,咱們還須要檢查這些資源是不是被總體使用,建立和刪除。該方法用來探測是否一個子資源應該是一個主資源。若是在刪除一個資源的時候,其子資源還能夠被其它資源重用,那麼該子資源實際上具備較高的重用性,應該是一個主資源。性能
- 單數 VS. 複數 :若是一個URL所對應的資源是使用複數表示的,那麼該類型的資源可能有多個。對該URL發送Get請求可能返回該資源的一個列表。反之,若是一個URL所對應的資源是使用單數表示的,那麼該類型的資源將只有一個,所以對該URL發送Get請求將只返回該資源的一個實例。
-
在判斷究竟是使用請求參數仍是相對路徑時,咱們通常分爲下面幾步。網站
首先,可選參數通常都應置於請求參數中。仍以egoods中的手機爲例。在選擇手機時,用戶能夠選擇品牌以及顏色。若是將品牌和顏色都定義在相對URL中,那麼具備特定品牌和顏色的手機將能夠經過兩個不一樣的URL訪問:/api/mobiles/brand/{brand}/color/{color}以及/api/mobiles/color/{color}/brand/{brand}。就用戶而言,其並沒有法瞭解這兩個URL所表示的是同一類資源仍是不一樣類型的資源。固然,您能夠說,咱們只用/api/mobiles/brand/{brand}/color/{color}。可是該URL將沒法處理用戶僅僅選擇了顏色,卻沒有選擇品牌的狀況。設計
其次,不是全部字符均可以在URL中被使用,如漢字,標點。爲了處理這種狀況,包含這些字符的篩選條件須要置於請求參數中。代理
最後,若是該特徵下包含子資源,那麼它自身也就是一個資源,所以須要以相對路徑的方式展示它。例如在egoods網站中,每件商品所屬於的分類僅僅是它的一個特徵。可是一個分類更包含了屬於它的各個品牌以及熱搜關鍵字等衆多信息。所以它實際上是一個資源,須要在URI路徑中表示它。接口
總的來講,既然使用HTTP來構建REST系統,那麼咱們就須要遵照URL各組成中的含義:URL中的相對路徑將用來標示「What I want」,也既對應着資源;而請求參數則用來標示「How I want」,即查看資源的方式。
- POST動詞會在目標URI之下建立一個新的子資源。PUT則是根據請求建立或修改特定位置的資源。此時向服務端發送的請求的目標URI須要包含所處理資源的ID:
- 獨立認證:每次發用戶名和密碼。代理認證:發送至代理,而後代理抹去狀態信息。