【Go API 开发实战 5】基础1:启动一个最简单的 RESTful API 服务器
本節核心內容
啟動一個最簡單的 RESTful API 服務器
設置 HTTP Header
API 服務器健康檢查和狀態查詢
編譯并測試 API
本小節源碼下載路徑:demo01
可先下載源碼到本地,結合源碼理解后續內容,邊學邊練。
如無特別說明,本教程的操作和編譯目錄均是 API 源碼的根目錄,并且本 API 服務器名字(也是二進制命令的名字)教程中統一叫作 apiserver。REST Web 框架選擇
要編寫一個 RESTful 風格的 API 服務器,首先需要一個 RESTful Web 框架,筆者經過調研選擇了 GitHub star 數最多的 Gin。采用輕量級的 Gin 框架,具有如下優點:高性能、擴展性強、穩定性強、相對而言比較簡潔(查看 性能對比)。關于 Gin 的更多介紹可以參考 Golang 微框架 Gin 簡介。
加載路由,并啟動 HTTP 服務
main.go 中的main()函數是 Go 程序的入口函數,在main()函數中主要做一些配置文件解析、程序初始化和路由加載之類的事情,最終調用http.ListenAndServe()在指定端口啟動一個 HTTP 服務器。本小節是一個簡單的 HTTP 服務器,僅初始化一個 Gin 實例,加載路由并啟動 HTTP 服務器。
編寫入口函數
編寫main()函數,main.go 代碼:
package mainimport ( "log""net/http"
"apiserver/router"
"github.com/gin-gonic/gin")func main() { // Create the Gin engine.
g := gin.New() // gin middlewares
middlewares := []gin.HandlerFunc{} // Routes.
router.Load( // Cores.
g, // Middlewares.
middlewares...,
)
log.Printf("Start to listening the incoming requests on http address: %s", ":8080")
log.Printf(http.ListenAndServe(":8080", g).Error())
}
加載路由
main()函數通過調用router.Load函數來加載路由(函數路徑為 router/router.go,具體函數實現參照 demo01/router/router.go):
"apiserver/handler/sd".... // The health check handlers
svcd := g.Group("/sd")
{
svcd.GET("/health", sd.HealthCheck)
svcd.GET("/disk", sd.DiskCheck)
svcd.GET("/cpu", sd.CPUCheck)
svcd.GET("/ram", sd.RAMCheck)
}
該代碼塊定義了一個叫 sd 的分組,在該分組下注冊了/health、/disk、/cpu、/ramHTTP 路徑,分別路由到sd.HealthCheck、sd.DiskCheck、sd.CPUCheck、sd.RAMCheck
函數。sd 分組主要用來檢查 API Server 的狀態:健康狀況、服務器硬盤、CPU 和內存使用量。具體函數實現參照 demo01/handler/sd/check.go。
設置 HTTP Header
router.Load函數通過g.Use()來為每一個請求設置 Header,在 router/router.go 文件中設置 Header:
g.Use(gin.Recovery())g.Use(middleware.NoCache)
g.Use(middleware.Options)
g.Use(middleware.Secure)
gin.Recovery():在處理某些請求時可能因為程序 bug 或者其他異常情況導致程序 panic,這時候為了不影響下一次請求的調用,需要通過gin.Recovery()來恢復 API 服務器
middleware.NoCache:強制瀏覽器不使用緩存
middleware.Options:瀏覽器跨域 OPTIONS 請求設置
middleware.Secure:一些安全設置
middleware包的實現見 demo01/router/middleware。
API 服務器健康狀態自檢
有時候 API 進程起來不代表 API 服務器正常,筆者曾經就遇到過這種問題:API 進程存在,但是服務器卻不能對外提供服務。因此在啟動 API 服務器時,如果能夠最后做一個自檢會更好些。筆者在 apiserver 中也添加了自檢程序,在啟動 HTTP 端口前 go 一個pingServer協程,啟動 HTTP 端口后,該協程不斷地 ping/sd/health路徑,如果失敗次數超過一定次數,則終止 HTTP 服務器進程。通過自檢可以最大程度地保證啟動后的 API 服務器處于健康狀態。自檢部分代碼位于 main.go 中:
func main() {.... // Ping the server to make sure the router is working.
go func() { if err := pingServer(); err != nil {
log.Fatal("The router has no response, or it might took too long to start up.", err)
}
log.Print("The router has been deployed successfully.")
}()
....
}// pingServer pings the http server to make sure the router is working.func pingServer() error { for i := 0; i < 10; i++ { // Ping the server by sending a GET request to `/health`.
resp, err := http.Get("http://127.0.0.1:8080" + "/sd/health") if err == nil && resp.StatusCode == 200 { return nil
}
// Sleep for a second to continue the next ping.
log.Print("Waiting for the router, retry in 1 second.")
time.Sleep(time.Second)
}
return errors.New("Cannot connect to the router.")
}
在pingServer()函數中,http.Get 向 http://127.0.0.1:8080/sd/health發送 HTTP GET 請求,如果函數正確執行并且返回的 HTTP StatusCode 為 200,則說明 API 服務器可用,pingServer函數輸出部署成功提示;如果超過指定次數,pingServer直接終止 API Server 進程,如下圖所示。
/sd/health 路徑會匹配到 handler/sd/check.go 中的 HealthCheck 函數,該函數只返回一個字符串:OK。
編譯源碼
下載 apiserver_demos 源碼包
$ git clone https://github.com/lexkong/apiserver_demos將 apiserver_demos/demo01 復制為 $GOPATH/src/apiserver
$ cp -a apiserver_demos/demo01/ $GOPATH/src/apiserver首次編譯需要下載vendor 包
因為 apiserver 功能比較豐富,需要用到很多 Go package,統計了下需要用到 60 個非標準 Go 包。為了讓讀者更容易地上手編寫代碼,這里將這些依賴用 go vendor 進行管理,并放在 GitHub 上供讀者下載安裝,安裝方法為:
$ cd $GOPATH/src$ git clone https://github.com/lexkong/vendor
? ?4.? ?進入 apiserver 目錄編譯源代碼
$ cd $GOPATH/src/apiserver$ gofmt -w .
$ go tool vet .
$ go build -v .
編譯后的二進制文件存放在當前目錄,名字跟目錄名相同:apiserver。
筆者建議每次編譯前對 Go 源碼進行格式化和代碼靜態檢查,以發現潛在的 Bug 或可疑的構造。
cURL 工具測試 API
cURL 工具簡介
本教程采用 cURL 工具來測試 RESTful API,標準的 Linux 發行版都安裝了 cURL 工具。cURL 可以很方便地完成對 REST API 的調用場景,比如:設置 Header,指定 HTTP 請求方法,指定 HTTP 消息體,指定權限認證信息等。通過-v選項也能輸出 REST 請求的所有返回信息。cURL 功能很強大,有很多參數,這里列出 REST 測試常用的參數:
-X/--request [GET|POST|PUT|DELETE|…] 指定請求的 HTTP 方法-H/--header 指定請求的 HTTP Header
-d/--data 指定請求的 HTTP 消息體(Body)
-v/--verbose 輸出詳細的返回信息
-u/--user 指定賬號、密碼
-b/--cookie 讀取 cookie
典型的測試命令為:
$ curl -v -XPOST -H "Content-Type: application/json" http://127.0.0.1:8080/user -d'{"username":"admin","password":"admin1234"}'啟動 API Server
$ ./apiserver[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
- using env: export GIN_MODE=release
- using code: gin.SetMode(gin.ReleaseMode)
[GIN-debug] GET /sd/health --> apiserver/handler/sd.HealthCheck (5 handlers)
[GIN-debug] GET /sd/disk --> apiserver/handler/sd.DiskCheck (5 handlers)
[GIN-debug] GET /sd/cpu --> apiserver/handler/sd.CPUCheck (5 handlers)
[GIN-debug] GET /sd/ram --> apiserver/handler/sd.RAMCheck (5 handlers)
Start to listening the incoming requests on http address: :8080
The router has been deployed successfully.
發送 HTTP GET 請求
$ curl -XGET http://127.0.0.1:8080/sd/healthOK
$ curl -XGET http://127.0.0.1:8080/sd/disk
OK - Free space: 16321MB (15GB) / 51200MB (50GB) | Used: 31%
$ curl -XGET http://127.0.0.1:8080/sd/cpu
CRITICAL - Load average: 2.39, 2.13, 1.97 | Cores: 2$ curl -XGET http://127.0.0.1:8080/sd/ram
OK - Free space: 455MB (0GB) / 8192MB (8GB) | Used: 5%
可以看到 HTTP 服務器均能正確響應請求。
小結
本小節通過具體的例子教讀者快速啟動一個 API 服務器,這只是一個稍微復雜點的 “Hello World”。讀者可以先通過該 Hello World 熟悉 Go API 開發流程,后續小節會基于這個簡單的 API 服務器,一步步構建一個企業級的 API 服務器。
本系列文章轉載自公眾號:騰訊游戲存儲與計算技術 微信號: game_infra
總結
以上是生活随笔為你收集整理的【Go API 开发实战 5】基础1:启动一个最简单的 RESTful API 服务器的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Go API 开发实战 7】基础 3:
- 下一篇: 【Go API 开发实战 6】基础 2: