RESTful 是目前最爲流行的一種互聯網軟件結構。由於它結構清晰、符合標準、易於理解、擴展方便,因此正獲得愈來愈多網站的採用。html
REST(REpresentational State Transfer),首次出如今 2000 年 Roy Thomas Fielding 的博士論文中,它指的是一組架構約束條件和原則。知足這些約束條件和原則的應用程序或設計就是 RESTful 的。git
綜上所述,咱們總結一下什麼是 RESTful 架構:github
一、每個 URI 表明一種資源web
二、客戶端和服務端之間,傳遞這種資源的某種表現層json
三、客戶端經過四個 HTTP 動詞,對服務端資源進行操做,實現「表現層狀態轉化」bash
將它們概述爲圖片形式,則 REST 架構圖爲:服務器
REST 的擴展性:網絡
RPC(Remote Procedure Call Protocol)遠程過程調用協議,是一種經過網絡從遠程計算機程序上請求服務,而不須要了解底層網絡技術的協議。它假定某些傳輸協議的存在,如 TCP 或 UDP,以便爲通訊程序之間攜帶信息數據。經過它可使函數調用模式網絡化。在 OSI 網絡通訊模型中,RPC 跨越了傳輸層和應用層。RPC 使得開發包括網絡分佈式多程序在內的應用程序更加容易。架構
運行時,一次客戶端對服務器的 RPC 調用,其內部操做大體有以下步驟:app
一、調用客戶端句柄;執行傳送參數
二、調用本地系統內核發送網絡消息
三、消息傳送到服務端
四、服務器句柄獲得消息並取得參數
五、執行遠程過程
六、執行的過程將結果返回服務器句柄
七、服務器句柄返回結果,調用遠程系統內核
八、消息傳回本地主機
九、客戶端句柄由內核接收消息
十、客戶端接收句柄返回的數據
在作 API 服務器開發時,不少人都會遇到這個問題 —— 選擇 REST 仍是 RPC。RPC 相比 REST 的優勢主要有 3 點:
一、RPC+Protobuf 採用的是 TCP 作傳輸協議,REST 直接使用 HTTP 作應用層協議,這種區別致使 REST 在調用性能上會比 RPC+Protobuf 低
二、RPC 不像 REST 那樣,每個操做都要抽象成對資源的增刪改查,在實際開發中,有不少操做很難抽象成資源,好比登陸操做。因此在實際開發中並不能嚴格按照 REST 規範來寫 API,RPC 就不存在這個問題
三、RPC 屏蔽網絡細節、易用,和本地調用相似
可是 REST 相較 RPC 也有不少優點:
一、輕量級,簡單易用,維護性和擴展性都比較好
二、REST 相對更規範,更標準,更通用,不管哪一種語言都支持 HTTP 協議,能夠對接外部不少系統,只要知足 HTTP 調用便可,更適合對外,RPC 會有語言限制,不一樣語言的 RPC 調用起來很麻煩
三、JSON 格式可讀性更強,開發調試都很方便
四、在開發過程當中,若是嚴格按照 REST 規範來寫 API,API 看起來更清晰,更容易被你們理解
其實業界廣泛採用的作法是,內部系統之間調用用 RPC,對外用 REST,由於內部系統之間可能調用很頻繁,須要 RPC 的高性能支撐。對外用 REST 更易理解,更通用些。
一個 RESTful 服務本質上首先是一個 Web service。下面是一個最簡單的 Web server,對於任何請求都簡單的直接返回請求連接:
package main import ( "fmt" "html" "log" "net/http" ) func main() { http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Hello, %q", html.EscapeString(r.URL.Path)) }) log.Fatal(http.ListenAndServe(":8080", nil)) }
編譯運行以後,使用 curl 測試,結果以下:
$ curl -v -XGET -H "Content-Type: application/json" http://127.0.0.1:8080/user Hello, "/user"
很顯然,咱們的線上項目不可能使用這麼簡單的 API 服務器。當用戶增長,請求也會不斷上漲,該如何處理好這些請求?做者使用了一個開源路由框架 mux。這是一個小巧高效,且使用較廣的第三方框架。接下來的篇幅裏,做者會使用 mux 搭建一個 API 服務器框架。
$go get github.com/gorilla/mux
//Router.go import ( "net/http" "github.com/gorilla/mux" ) type Route struct { Name string Method string Pattern string HandlerFunc http.HandlerFunc } type Routes []Route func NewRouter() *mux.Router { router := mux.NewRouter().StrictSlash(true) for _, route := range routes { var handler http.Handler handler = route.HandlerFunc handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { handler.ServeHTTP(w, r) }) router.Methods(route.Method).Path(route.Pattern).Name(route.Name).Handler(handler) } return router } var routes = Routes{ Route{ "DeleteItem", "DELETE", "/v1/delete", v1_deleteItem, }, ... }
//Handler.go func v1_deleteItem(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json; charset=UTF-8") w.WriteHeader(http.StatusOK) if err := json.NewEncoder(w).Encode(jsonErr{Code: http.StatusOK, Text: "操做成功"}); err != nil { log.print("%s\n%s", err.Error(), debug.Stack()) } }
總體 mux 功能實現:
//main.go func main() { router := NewRouter() log.print("service running(PID:%d)...", os.Getpid()) log.Fatal(http.ListenAndServe(":8080", router)) }
API 基本框架已經實現,接下來就是將相應功能實現模塊與相應接口對接便可。
對於想要學習做爲一個客戶端開發者如何獨立完成一個具備 API 服務器功能的線上 APP,能夠參考專欄《如何獨立開發一個完整應用》,專欄中使用線上 APP 靚手藝 做爲案例,詳細分享了筆者如何實現 APP 所有功能。