使用 gin 搭建 api 後臺系統之框架搭建
gin 是 golang 中比較流行的框架,很多系統都是在該框架下開發的,這個框架給我的感覺像是 Flask 在 python 中的位置,基礎的功能都有,但是如果想要很好的使用,還需要開發很多自己的功能與中間件,在看過不少的教程以後,想要記錄一下學習過程中遇到的各種問題。
本系列簡單的實現了一些做後臺服務的能用方法,如獲取參數,數據庫查詢等操作,項目的整體還談不上架構,頂多算是個 quick start, 目錄結構也不那麼講究,因爲初學,所以肯定會有很多問題。以後再一點點地實踐一點點地修改吧。
下載 gin
第一篇,簡單一些,先把框架搭起來,寫個 hello world 出來。
項目基於 go module 方式,在一個空目錄中運行 go mod init gintest
初始化項目,go 會自動生成一個 go.mod 文件
在 go.mod 文件中添加 gin
module gintest
go 1.15
require (
github.com/gin-gonic/gin v1.7.4
)
之後使用go mod download
命令下載。
或者在項目目錄中直接運行 go get github.com/gin-gonic/gin@v1.7.4
命令,也會下載 gin 包,並且會自動添加到 go.mod 文件中。
構建 http 服務
新建一個 server.go 文件,寫入以下代碼
package main
import "github.com/gin-gonic/gin"
func main() {
r := gin.Default()
r.GET("/", func(c *gin.Context) {
c.JSON(200, gin.H{
"Msg":"Hello World",
})
})
r.Run(":8080")
}
代碼很簡單,運行go run server.go
則會在 8080 端口啓動一個 http 服務,使用瀏覽器訪問 http://127.0.0.1:8080/
則會返回 json 的數據
{
Msg: "Hello world"
}
上面代碼中,使用gin.Default()
創建一個默認的 gin 應用,這個應用底層初始化了很多設置,這裏就先不深入探索了。
這裏就註冊了一個路由,/
,它的處理由一個匿名函數來處理, gin 中的 GET 方法的定義爲
// GET is a shortcut for router.Handle("GET", path, handle).
func (group *RouterGroup) GET(relativePath string, handlers ...HandlerFunc) IRoutes {
return group.handle(http.MethodGet, relativePath, handlers)
}
handler 爲處理方法,該方法的定義爲
type HandlerFunc func(*Context)
所以這裏需要一個參數爲 (*Context) 的函數,上面的代碼中使用
func(c *gin.Context) {
c.JSON(200, gin.H{
"Msg":"Hello World",
})
}
這個匿名函數來處理 /
的 GET 請求。
這裏還可以定義 POST、DELETE、PUT 等方法,這樣可以很方便的編寫 restful 風格的 API,
r.POST("/", func(c *gin.Context) {
c.JSON(200, gin.H{
"Msg":"Hello world POST",
})
})
404 配置
默認的 404 處理,會打印 404 not found,更多的時候,我們想自定義 404 頁面的處理,這時可以通過設置r.NoRoute
方法來實現
r.NoRoute(func(c *gin.Context) {
c.JSON(404, gin.H{
"Msg": "The page not found",
})
})
這時在訪問一個不存在的路由時會展示自定義的內容。
路由組
很多時候,我們是有這樣的需求,訪問的路由前面都有統一的前綴,如/api/v1
, 或者/user
,當然可以在定義路由的時候都統一寫上前綴,但是這種方式,如果後期修改了前綴將要改好多地方。這裏可以使用路由組的概念。
func main() {
r := gin.Default()
r.GET("/", func(c *gin.Context) {
c.JSON(200, gin.H{
"Msg": "Hello world",
})
})
apiv1 := r.Group("/api/v1")
{
apiv1.GET("/", func(c *gin.Context) {
c.JSON(200, gin.H{"msg": "hello api v1"})
})
}
r.Run(":8080")
}
以上代碼,定義了一個路由組,/api/v1
, 之後又會在該路由組下定義相應的處理方法,這裏區分 http://127.0.0.1:8080/
這個 url 返回 "Msg": "Hello world"
, /api/v1/
這個路由返回 "msg": "hello api v1"
處理類的封裝
上面的路由的處理類都是使用匿名函數,處理的邏輯比較簡單的話,可以這麼寫,但是還是不建議寫個匿名函數來處理,之後隨着項目越來越大,這裏的路由定義會越來越多,如果還有大量的匿名函數的話,看着就會比較亂。
這裏我們可以將處理 handler 進行封裝。
先創建一個 handlers 的文件夾,寫入以下代碼
package handlers
import "github.com/gin-gonic/gin"
type ApiV1 struct {
}
func (ApiV1) Get(c *gin.Context) {
c.JSON(200, gin.H{"msg": "handlers get request!"})
}
這裏定義了一個 ApiV1 的結構體, 之後定義了一個 Get 方法,然後在入口 server.go 文件中,修改原來的代碼,
func main() {
r := gin.Default()
apiv1_h := handlers.ApiV1{}
r.GET("/", func(c *gin.Context) {
c.JSON(200, gin.H{
"Msg": "Hello world",
})
})
apiv1 := r.Group("/api/v1")
{
apiv1.GET("/", apiv1_h.Get)
}
r.Run(":8080")
}
使用apiv1_h := handlers.ApiV1{}
初始化一個 ApiV1 的結構體對象,在之後路由定義的時候,就可以直接使用該對象的 Get 方法,最好將相同前綴的放入一個括號中{}
, 方法查看
{
apiv1.GET("/", apiv1_h.Get)
}
這裏注意,處理 handler 爲 apiv1_h.Get
, 而不是 apiv1_h.Get(c, *gin.Context)
使用 http.Server 啓動服務
上面的代碼都是以r.run(":8080")
的方式啓動服務,但是有時候我們希望做一些個性化的設置,如一些讀寫超時,當然也可以調用gin.New()
方法中得到的對象中進行設置,也可以直接使用http.Server
中定義。
func main() {
r := gin.Default()
apiv1_h := handlers.ApiV1{}
apiv1 := r.Group("/api/v1")
{
apiv1.GET("/", apiv1_h.Get)
}
s := &http.Server{
Addr: ":8080",
Handler: r,
ReadTimeout: 10*time.Second,
WriteTimeout: 10*time.Second,
}
err := s.ListenAndServe()
if err != nil {
return
}
}
網頁跳轉
上面的代碼在處理請求的時候,都是返回 json 數據,由於現在主流開發使用前後端分離的模式,所以這裏不太使用 html 模板的方式返回數據了。
當使用第三方登錄的時候,全牽扯到網頁跳轉,網頁跳轉也非常簡單, 修改 apiv1.go 文件
package handlers
import "github.com/gin-gonic/gin"
type ApiV1 struct {
}
func (*ApiV1) Get(c *gin.Context) {
c.Redirect(301, "https://www.baidu.com")
}
這樣在方法的對應的路由的時候,就會跳轉到百度了。
這裏要注意,狀態碼必須處理 300-308 之間,否則會報錯
func (r Redirect) Render(w http.ResponseWriter) error {
if (r.Code < http.StatusMultipleChoices || r.Code > http.StatusPermanentRedirect) && r.Code != http.StatusCreated {
panic(fmt.Sprintf("Cannot redirect with status code %d", r.Code))
}
http.Redirect(w, r.Request, r.Location, r.Code)
return nil
}
gin 框架的基本搭建先記錄到這裏,之後會介紹各種請求參數的獲取與校驗。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/fqNvwrjK08nU2oO7qwQesA