Go Gin 框架

簡介

中文官網:https://gin-gonic.com/zh-cn/docs/introduction/

github:https://github.com/gin-gonic/gin

Gin 是一個用 Go (Golang) 編寫的 Web 框架。 它具有類似 martini 的 API,性能要好得多,多虧了 httprouter,速度提高了 40 倍。 如果您需要性能和良好的生產力,您一定會喜歡 Gin

  • Go 1.13 及以上版本

特性

1.快速

基於 Radix 樹的路由,小內存佔用。沒有反射。可預測的 API 性能。

2.支持中間件

傳入的 HTTP 請求可以由一系列中間件和最終操作來處理。 例如:Logger,Authorization,GZIP,最終操作 DB。

3.Crash 處理

Gin 可以 catch 一個發生在 HTTP 請求中的 panic 並 recover 它。這樣,你的服務器將始終可用。例如,你可以向 Sentry 報告這個 panic!

4.JSON 驗證

Gin 可以解析並驗證請求的 JSON,例如檢查所需值的存在。

5.路由組

更好地組織路由。是否需要授權,不同的 API 版本…… 此外,這些組可以無限制地嵌套而不會降低性能。

6.錯誤管理

Gin 提供了一種方便的方法來收集 HTTP 請求期間發生的所有錯誤。最終,中間件可以將它們寫入日誌文件,數據庫並通過網絡發送。

7.內置渲染

Gin 爲 JSON,XML 和 HTML 渲染提供了易於使用的 API。

8.可擴展性

新建一箇中間件非常簡單,去查看示例代碼吧。

hello world

初始化項目

新建一個gin_test ,文件夾,使用vsocd打開在終端輸入一下命令,初始化項目

# 初始化模塊
go mod init gin_test
# 下載並安裝
go get -u github.com/gin-gonic/gin

image-20230207144445059

main.go

創建main.go,並寫入下面的代碼

package main

// 將 gin 引入到代碼中
import "github.com/gin-gonic/gin"

// (可選)如果使用諸如 http.StatusOK 之類的常量,則需要引入 net/http 包
// import "net/http"

func main() {
	r := gin.Default()
	r.GET("/ping", func(c *gin.Context) {
		c.JSON(200, gin.H{
			"message": "pong",
		})
	})
	r.Run() // 監聽並在 0.0.0.0:8080 上啓動服務
}

啓動

# 運行 main.go 並且在瀏覽器中訪問 HOST_IP:8080/ping
go run main.go

訪問

http://localhost:8080/ping

image-20230207145048739

第一個例子完成

自定義路由

上面那個例子,路由定義和控制器處理都在main函數裏面,在真實項目中顯然是不可能的,難道你想看到一個文件兩三萬行?雖然我真的見過...,但是要儘量避免這種情況,所以我們一般把路由文件獨立出來一個文件,甚至幾個文件,那在Gin 裏面要怎麼做呢?往下看

拆分成單個路由文件

新建routes文件夾,在此文件下新建router1.go文件,內容如下

目錄結構

│  go.mod
│  go.sum
│  main.go
└─routers
        router1.go

案例

文件:routes/router1.go

package gin_test

import "github.com/gin-gonic/gin"

// 控制器方法
func helloHandler(context *gin.Context) {
	context.JSON(200, "這是路由文件1")
}

// 設置路由
func SetupRouter() *gin.Engine {
	// 配置路由信息
	router := gin.Default()
	router.GET("/router1", helloHandler)
	return router
}

文件:main.go

package main

import (
	"fmt"

	// 引入自定義路由模塊
	routers "gin_test/routers"
)

func main() {
	// 獲取路由
	router := routers.SetupRouter()
	// 啓動監聽並打印錯誤
	if err := router.Run(); err != nil {
		fmt.Println(err)
		return
	}
}

啓動

go run main.go

訪問

http://localhost:8080/router1

image-20230208160443833

到此將路由單獨拆出來已經可以了

支持多個路由文件

當我們的業務規模繼續膨脹,單獨的一個router1.go文件或包已經滿足不了我們的需求了,我們需要按模塊或者按業務拆分成多個路由文件,在Gin 中怎麼實現?看下面

目錄結構

│  go.mod
│  go.sum
│  main.go
└─routes
        router1.go
        router2.go

這時候,多個路由文件我們看做不同的模塊,爲了防止兩個不同模塊之間有同名路由,我們最好加上路由組

官方文檔:https://gin-gonic.com/zh-cn/docs/examples/grouping-routes/

我們就按文件名設置路由組吧,

  • router1.go -> router1
  • router2.go -> router2

這個時候我們就不能將路由初始化分到路由文件裏了,而是在main函數中初始化路由,將路由器傳入路由文件的方法裏,也就是說路由文件只負責註冊路由

案例

文件:routes/router1.go

package gin_test

import "github.com/gin-gonic/gin"

// 控制器方法
func helloHandler1(context *gin.Context) {
	context.JSON(200, "這是路由文件1")
}

// 設置路由
func Router1(router *gin.Engine) {
	// 設置路由組
	router1 := router.Group("/router1")
	{
		// 註冊模塊1的路由
		router1.GET("/hello", helloHandler1)
	}
}

文件:routes/router2.go

package gin_test

import "github.com/gin-gonic/gin"

// 控制器方法
func helloHandler2(context *gin.Context) {
	context.JSON(200, "這是路由文件2")
}

// 設置路由
func Router2(router *gin.Engine) {
	// 設置路由組
	router2 := router.Group("/router2")
	{
		// 註冊模塊2的路由
		router2.GET("/hello", helloHandler2)
	}
}

文件:main.go

package main

import (
	"fmt"

	// 引入自定義路由模塊
	routers "gin_test/routers"

	"github.com/gin-gonic/gin"
)

func main() {
	// 獲取路由
	router := gin.Default()
	routers.Router1(router)
	routers.Router2(router)
	// 啓動監聽並打印錯誤
	if err := router.Run(); err != nil {
		fmt.Println(err)
		return
	}
}

啓動

go run main.go

訪問

http://localhost:8080/router2/hello

image-20230208164417599

至此我們支持了多個路由文件,並且使用路由組避免了同路徑路由註冊失敗的問題

路由拆分到不同平臺

上面我們已經支持了多個文件,並且支持路由分組,但是有時候項目規模實在太大,比如:

我們需要拆分成:

  • web:web訪問的路由
  • app:app訪問的路由
  • common: 公共的基礎路由,web和app都可以訪問

上面這種在項目體量大的時候,還是很常見的,那在Gin 中該怎麼寫

目錄結構

│  go.mod
│  go.sum
│  main.go
├─app
│      router.go
├─common
│      router.go
├─routers
│      routers.go
└─web
       router.go

文件:main.go

package main

import (
	"fmt"

	// 引入自定義路由模塊
	app "gin_test/app"
	common "gin_test/common"
	routers "gin_test/routers"
	web "gin_test/web"
)

func main() {
	// 加載所有模塊的路由配置
	routers.Include(app.Routers, web.Routers, common.Routers)
	// 初始化路由
	router := routers.Init()
	// 啓動監聽並打印錯誤
	if err := router.Run(); err != nil {
		fmt.Println(err)
		return
	}
}

文件:routers/routers.go

package routers

import (
	"github.com/gin-gonic/gin"
)

// 定義單個路由model
type RouterModel func(router *gin.Engine)

// 路由model 切片
var routerModels = make([]RouterModel, 0)

// 註冊路由model配置
func Include(models ...RouterModel) {
	// 塞到路由模塊切片中
	routerModels = append(routerModels, models...)
}

// 初始化路由
func Init() *gin.Engine {
	router := gin.Default()
	for _, model := range routerModels {
		model(router)
	}
	return router
}

文件:web/router.go

package gin_test

import "github.com/gin-gonic/gin"

// 控制器方法
func hello(context *gin.Context) {
	context.JSON(200, "這是 Web 模塊")
}

// 設置路由
func Routers(router *gin.Engine) {
	// 設置路由組
	Web := router.Group("/Web")
	{
		// 註冊路由
		Web.GET("/hello", hello)
	}
}

文件:app/router.go

package gin_test

import "github.com/gin-gonic/gin"

// 控制器方法
func hello(context *gin.Context) {
	context.JSON(200, "這是app模塊")
}

// 設置路由
func Routers(router *gin.Engine) {
	// 設置路由組
	App := router.Group("/App")
	{
		// 註冊路由
		App.GET("/hello", hello)
	}
}

文件:common/router.go

package gin_test

import "github.com/gin-gonic/gin"

// 控制器方法
func hello(context *gin.Context) {
	context.JSON(200, "這是 Common 模塊")
}

// 設置路由
func Routers(router *gin.Engine) {
	// 設置路由組
	Common := router.Group("/Common")
	{
		// 註冊路由
		Common.GET("/hello", hello)
	}
}

啓動

go run main.go

路由

image-20230208172855610

請求

http://localhost:8080/App/hello

image-20230208172933664

代碼

這個demo 代碼我放在了這裏:

https://gitee.com/makalochen/go-test/tree/master/gin_test

結語

其他什麼參數獲取,上傳文件,自定義驗證啥,在官方文檔都可以找到,我就不寫了,我只能說寫的再好也沒官方給的標準

官網中文文檔地址:

https://gin-gonic.com/zh-cn/docs/examples/

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