實現一個 RESTful API 服務器

RESTful 是目前最爲流行的一種互聯網軟件結構。因爲它結構清晰、符合標準、易於理解、擴展方便,所以正得到越來越多網站的採用。

什麼是 REST

REST(REpresentational State Transfer),首次出現在 2000 年 Roy Thomas Fielding 的博士論文中,它指的是一組架構約束條件和原則。滿足這些約束條件和原則的應用程序或設計就是 RESTful 的。

  • 資源(Resources),REST 是“表現層狀態轉化”,其實它省略了主語。“表現層”其實指的是“資源”的“表現層”。那麼什麼是資源呢?我們平時網上訪問到圖片、文字、文檔、多媒體等就是資源,一般通過 URI 來定位。也就是說,一個 URI 就表示一個資源。
  • 表現層(Representation),資源是作爲一個具體的實體信息,它可以有多種的展現方式。而把實體展現出來就是表現層。例如一個 txt 文本信息,它可以輸出成 html、json 等。
  • 狀態轉化(State Transfer),訪問一個網站,就代表了客戶端和服務器的一個互動過程。在這個過程中,就涉及到數據和狀態的變化。而 HTTP 協議是無狀態的,那麼這些狀態肯定保存在服務器端,所以如果客戶端想要通知服務器端改變數據和狀態的變化,就要通過某種方式來通知它。客戶端能通知服務器端的手段,只能是 HTTP 協議。具體來說,就是 HTTP 協議裏面,四個表示操作方式的動詞:GET、POST、PUT、DELETE。它們分別對應四種基本操作:GET 用來獲取資源,POST 用來新建資源(也可以用於更新資源),PUT 用來更新資源,DELETE 用來刪除資源。

綜上所述,我們總結一下什麼是 RESTful 架構:

1、每一個 URI 代表一種資源

2、客戶端和服務端之間,傳遞這種資源的某種表現層

3、客戶端通過四個 HTTP 動詞,對服務端資源進行操作,實現“表現層狀態轉化”

將它們概述爲圖片形式,則 REST 架構圖爲:

REST架構圖.png

REST 的擴展性:

REST的擴展性.png

什麼是 RPC

RPC(Remote Procedure Call Protocol)遠程過程調用協議,是一種通過網絡從遠程計算機程序上請求服務,而不需要了解底層網絡技術的協議。它假定某些傳輸協議的存在,如 TCP 或 UDP,以便爲通信程序之間攜帶信息數據。通過它可以使函數調用模式網絡化。在 OSI 網絡通信模型中,RPC 跨越了傳輸層和應用層。RPC 使得開發包括網絡分佈式多程序在內的應用程序更加容易。

工作原理

RPC工作流程圖.png

運行時,一次客戶端對服務器的 RPC 調用,其內部操作大致有如下步驟:

1、調用客戶端句柄;執行傳送參數

2、調用本地系統內核發送網絡消息

3、消息傳送到服務端

4、服務器句柄得到消息並取得參數

5、執行遠程過程

6、執行的過程將結果返回服務器句柄

7、服務器句柄返回結果,調用遠程系統內核

8、消息傳回本地主機

9、客戶端句柄由內核接收消息

10、客戶端接收句柄返回的數據

REST vs RPC

在做 API 服務器開發時,很多人都會遇到這個問題 —— 選擇 REST 還是 RPC。RPC 相比 REST 的優點主要有 3 點:

1、RPC+Protobuf 採用的是 TCP 做傳輸協議,REST 直接使用 HTTP 做應用層協議,這種區別導致 REST 在調用性能上會比 RPC+Protobuf 低

2、RPC 不像 REST 那樣,每一個操作都要抽象成對資源的增刪改查,在實際開發中,有很多操作很難抽象成資源,比如登錄操作。所以在實際開發中並不能嚴格按照 REST 規範來寫 API,RPC 就不存在這個問題

3、RPC 屏蔽網絡細節、易用,和本地調用類似

但是 REST 相較 RPC 也有很多優勢:

1、輕量級,簡單易用,維護性和擴展性都比較好

2、REST 相對更規範,更標準,更通用,無論哪種語言都支持 HTTP 協議,可以對接外部很多系統,只要滿足 HTTP 調用即可,更適合對外,RPC 會有語言限制,不同語言的 RPC 調用起來很麻煩

3、JSON 格式可讀性更強,開發調試都很方便

4、在開發過程中,如果嚴格按照 REST 規範來寫 API,API 看起來更清晰,更容易被大家理解

其實業界普遍採用的做法是,內部系統之間調用用 RPC,對外用 REST,因爲內部系統之間可能調用很頻繁,需要 RPC 的高性能支撐。對外用 REST 更易理解,更通用些。

一個基本的 Web Server

一個 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 服務器框架。

安裝 mux

$go get github.com/gorilla/mux

Router

//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

//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 全部功能。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章