簡介
近幾年微服務是如火如荼的在發展,而微服務之間的呼叫和漸漸的從RPC呼叫轉移到了HTTP呼叫。於是經常聽到有些同事說我們提供微服務並且暴露RESTful介面給別的系統,但是什麼是RESTful介面呢?它和REST有什麼關係呢?
別急,本文將會帶你一探究竟。
REST
REST是一種架構。
首先我們要記住的是REST是一種架構方式,並不是一種協議。它只是告訴我們應該如何去搭建一個可靠的系統。
REST的全稱是REpresentational State Transfer。中文可能不好翻譯,我們暫將其定義為有代表性的狀態轉義。它是分散式系統的一種架構方式。最先是由Roy Fielding在2000年他的博士畢業論文中首先提到的。
REST架構在現在的web應用中非常常見,它並不涉及到具體的編碼,它只是一種高階比的指導方案,具體的實現還是由你自己決定。
REST和RESTful API
我們剛剛講解了REST,那麼REST和RESTful API有什麼關係呢?
我們知道,API是服務和服務之間,客戶端和服務端之間溝通的橋樑,通過API之間的呼叫,我們可以從伺服器中獲取到需要的資源資訊。而RESTful API就是符合REST架構的API。
所以不是所有的HTTP協議的API都是RESTful API,它的前提是你的系統是REST架構的。
REST架構的基本原則
那麼什麼樣的系統才能被稱為是REST架構的系統呢?根據Roy Fielding的論文描述,REST架構的系統有6個基本特徵。我們一一來說明。
Uniform interface統一的介面
在REST架構中,最為核心的元素就是資源。我們將資源定義為一個個的獨立的URI。一個資源用一個獨立並且唯一的URI來表示。
單個的資源不能太大也不能太小,它表示的是一個獨立的可以操作的單位。這些資源通過通用的獲取方式來進行獲取和操作。比如對資源的CURD可以分別用不同的HTTP method來表示(PUT,POST,GET,DELETE)。
同時需要對資源進行統一的命名,定義統一的link格式和資料格式。
還有一點,根據HATEOAS協議,一個資源還應該包含指向該資源或者相關資源的URI。可以能有些同學現在對這一點還有些疑惑,不過沒關係,後面我們會詳細對HATEOAS進行講解。
Spring也提供了對HATEOAS的支援,我們看一個基本的HATEOAS的請求:
GET http://localhost:8080/greeting
該請求的返回可以是這樣的:
{
"content":"Hello, World!",
"_links":{
"self":{
"href":"http://localhost:8080/greeting?name=World"
}
}
}
大家可以看到上面返回了一個代表自己URI的資源連結。
Client–server 客戶端和伺服器端獨立
另外的一條規則就是客戶端和伺服器端獨立,客戶端和伺服器端互不影響,他們之間的唯一互動就是API的呼叫。
對於客戶端來說只要能夠通過API獲取到對應的資源即可,並不關心伺服器是怎麼實現的。
而對於伺服器端來說,只需要提供保持不變的API即可,自己內部的實現可以自由決定,也不需要考慮客戶端是如何使用這些API的。
這條規則對於現在的很多前後端分離的架構來說已經使用了。
Stateless無狀態
和HTTP協議一樣,REST架構中各個服務之間的API呼叫也是無狀態的。無狀態的意思是伺服器並不儲存API呼叫的歷史記錄,也不儲存任何關於客戶端的資訊。對於伺服器來說,每個請求都是最新的。
所以使用者的狀態資訊是在客戶端進行儲存和維護的,客戶端需要在每個介面帶上可以識別使用者的唯一標記,從而在伺服器端進行認證和識別,從而獲取到對應的資源。
Cacheable可快取
快取是提升系統速度的利器,對於REST的資源也是一樣的,在REST中對於可快取的資源需要標明它是可以被快取的。
從而對應的呼叫方可以將這些資源進行快取,從而提升系統的效率。
Layered system分層系統
現代的系統基本上都是分層的,在REST架構中也是一樣,只要保證對外提供的資源URI是一致的,架構並不關心你到底使用的是幾層架構。
Code on demand按需編碼
一般來說,REST架構中各個服務通常是通過JSON或者XML來進行互動的。但是這並不是硬性規定。可以返回可執行的程式碼直接執行。
RESTful API的例子
我們來舉幾個常見的RESTful API的例子,來見識一下這種架構的神奇之處:
請求一個entity:
GET https://services.odata.org/TripPinRESTierService/People
根據ID請求一個entity:
GET https://services.odata.org/TripPinRESTierService/People('russellwhyte')
請求一個entity的某個屬性:
GET https://services.odata.org/TripPinRESTierService/Airports('KSFO')/Name
使用filter進行查詢:
GET https://services.odata.org/TripPinRESTierService/People?$filter=FirstName eq 'Scott'
修改資料:
POST https://services.odata.org/TripPinRESTierService/People
header:
{
Content-Type: application/json
}
body:
{
"UserName":"lewisblack",
"FirstName":"Lewis",
"LastName":"Black",
"Emails":[
"lewisblack@example.com"
],
"AddressInfo": [
{
"Address": "187 Suffolk Ln.",
"City": {
"Name": "Boise",
"CountryRegion": "United States",
"Region": "ID"
}
}
]
}
刪除資料:
DELETE https://services.odata.org/TripPinRESTierService/People('russellwhyte')
更新資料:
PATCH https://services.odata.org/TripPinRESTierService/People('russellwhyte')
header:
{
Content-Type: application/json
}
body:
{
"FirstName": "Mirs",
"LastName": "King"
}
總結
本文講解了REST和RESTful相關的概念,那麼對於其中最重要的資源如何定義呢?敬請期待後續文章。
本文已收錄於 http://www.flydean.com/01-rest-restful/
最通俗的解讀,最深刻的乾貨,最簡潔的教程,眾多你不知道的小技巧等你來發現!