RESTful,是目前最為流行的一種互聯(lián)網(wǎng)軟件架構(gòu)。因為它結(jié)構(gòu)清晰、符合標準、易于理解、擴展方便,所以正得到越來越多網(wǎng)站的采用。本小節(jié)我們將來學習它到底是一種什么樣的架構(gòu)?以及在Go里面如何來實現(xiàn)它。
REST(REpresentational State Transfer)這個概念,首次出現(xiàn)是在 2000年Roy Thomas Fielding(他是HTTP規(guī)范的主要編寫者之一)的博士論文中,它指的是一組架構(gòu)約束條件和原則。滿足這些約束條件和原則的應用程序或設計就是RESTful的。
要理解什么是REST,我們需要理解下面幾個概念:
資源(Resources) REST是"表現(xiàn)層狀態(tài)轉(zhuǎn)化",其實它省略了主語。"表現(xiàn)層"其實指的是"資源"的"表現(xiàn)層"。
那么什么是資源呢?就是我們平常上網(wǎng)訪問的一張圖片、一個文檔、一個視頻等。這些資源我們通過URI來定位,也就是一個URI表示一個資源。
表現(xiàn)層(Representation)
資源是做一個具體的實體信息,他可以有多種的展現(xiàn)方式。而把實體展現(xiàn)出來就是表現(xiàn)層,例如一個txt文本信息,他可以輸出成html、json、xml等格式,一個圖片他可以jpg、png等方式展現(xiàn),這個就是表現(xiàn)層的意思。
URI確定一個資源,但是如何確定它的具體表現(xiàn)形式呢?應該在HTTP請求的頭信息中用Accept和Content-Type字段指定,這兩個字段才是對"表現(xiàn)層"的描述。
狀態(tài)轉(zhuǎn)化(State Transfer)
訪問一個網(wǎng)站,就代表了客戶端和服務器的一個互動過程。在這個過程中,肯定涉及到數(shù)據(jù)和狀態(tài)的變化。而HTTP協(xié)議是無狀態(tài)的,那么這些狀態(tài)肯定保存在服務器端,所以如果客戶端想要通知服務器端改變數(shù)據(jù)和狀態(tài)的變化,肯定要通過某種方式來通知它。
客戶端能通知服務器端的手段,只能是HTTP協(xié)議。具體來說,就是HTTP協(xié)議里面,四個表示操作方式的動詞:GET、POST、PUT、DELETE。它們分別對應四種基本操作:GET用來獲取資源,POST用來新建資源(也可以用于更新資源),PUT用來更新資源,DELETE用來刪除資源。
綜合上面的解釋,我們總結(jié)一下什么是RESTful架構(gòu):
Web應用要滿足REST最重要的原則是:客戶端和服務器之間的交互在請求之間是無狀態(tài)的,即從客戶端到服務器的每個請求都必須包含理解請求所必需的信息。如果服務器在請求之間的任何時間點重啟,客戶端不會得到通知。此外此請求可以由任何可用服務器回答,這十分適合云計算之類的環(huán)境。因為是無狀態(tài)的,所以客戶端可以緩存數(shù)據(jù)以改進性能。
另一個重要的REST原則是系統(tǒng)分層,這表示組件無法了解除了與它直接交互的層次以外的組件。通過將系統(tǒng)知識限制在單個層,可以限制整個系統(tǒng)的復雜性,從而促進了底層的獨立性。
下圖即是REST的架構(gòu)圖:
當REST架構(gòu)的約束條件作為一個整體應用時,將生成一個可以擴展到大量客戶端的應用程序。它還降低了客戶端和服務器之間的交互延遲。統(tǒng)一界面簡化了整個系統(tǒng)架構(gòu),改進了子系統(tǒng)之間交互的可見性。REST簡化了客戶端和服務器的實現(xiàn),而且對于使用REST開發(fā)的應用程序更加容易擴展。
下圖展示了REST的擴展性:
Go沒有為REST提供直接支持,但是因為RESTful是基于HTTP協(xié)議實現(xiàn)的,所以我們可以利用net/http
包來自己實現(xiàn),當然需要針對REST做一些改造,REST是根據(jù)不同的method來處理相應的資源,目前已經(jīng)存在的很多自稱是REST的應用,其實并沒有真正的實現(xiàn)REST,我暫且把這些應用根據(jù)實現(xiàn)的method分成幾個級別,請看下圖:
上圖展示了我們目前實現(xiàn)REST的三個level,我們在應用開發(fā)的時候也不一定全部按照RESTful的規(guī)則全部實現(xiàn)他的方式,因為有些時候完全按照RESTful的方式未必是可行的,RESTful服務充分利用每一個HTTP方法,包括DELETE和PUT??捎袝r,HTTP客戶端只能發(fā)出GET和POST請求:
我們現(xiàn)在可以通過POST里面增加隱藏字段_method這種方式可以來模擬PUT、DELETE等方式,但是服務器端需要做轉(zhuǎn)換。我現(xiàn)在的項目里面就按照這種方式來做的REST接口。當然Go語言里面完全按照RESTful來實現(xiàn)是很容易的,我們通過下面的例子來說明如何實現(xiàn)RESTful的應用設計。
package main
import (
"fmt"
"github.com/drone/routes"
"net/http"
)
func getuser(w http.ResponseWriter, r *http.Request) {
params := r.URL.Query()
uid := params.Get(":uid")
fmt.Fprintf(w, "you are get user %s", uid)
}
func modifyuser(w http.ResponseWriter, r *http.Request) {
params := r.URL.Query()
uid := params.Get(":uid")
fmt.Fprintf(w, "you are modify user %s", uid)
}
func deleteuser(w http.ResponseWriter, r *http.Request) {
params := r.URL.Query()
uid := params.Get(":uid")
fmt.Fprintf(w, "you are delete user %s", uid)
}
func adduser(w http.ResponseWriter, r *http.Request) {
uid := r.FormValue("uid")
fmt.Fprint(w, "you are add user %s", uid)
}
func main() {
mux := routes.New()
mux.Get("/user/:uid", getuser)
mux.Post("/user/", adduser)
mux.Del("/user/:uid", deleteuser)
mux.Put("/user/:uid", modifyuser)
http.Handle("/", mux)
http.ListenAndServe(":8088", nil)
}
上面的代碼演示了如何編寫一個REST的應用,我們訪問的資源是用戶,我們通過不同的method來訪問不同的函數(shù),這里使用了第三方庫github.com/drone/routes,在前面章節(jié)我們介紹過如何實現(xiàn)自定義的路由器,這個庫實現(xiàn)了自定義路由和方便的路由規(guī)則映射,通過它,我們可以很方便的實現(xiàn)REST的架構(gòu)。通過上面的代碼可知,REST就是根據(jù)不同的method訪問同一個資源的時候?qū)崿F(xiàn)不同的邏輯處理。
REST是一種架構(gòu)風格,汲取了WWW的成功經(jīng)驗:無狀態(tài),以資源為中心,充分利用HTTP協(xié)議和URI協(xié)議,提供統(tǒng)一的接口定義,使得它作為一種設計Web服務的方法而變得流行。在某種意義上,通過強調(diào)URI和HTTP等早期Internet標準,REST是對大型應用程序服務器時代之前的Web方式的回歸。目前Go對于REST的支持還是很簡單的,通過實現(xiàn)自定義的路由規(guī)則,我們就可以為不同的method實現(xiàn)不同的handle,這樣就實現(xiàn)了REST的架構(gòu)。
更多建議: