Skip to content
GitHub

Go Gin

Gin 官网

Gin 是一个用 Go (Golang) 编写的 HTTP Web 框架

使用 go get -u 下载最新的 gin 包, 同时把依赖信息写入 go.mod

 $ go env -w GOPROXY=https://goproxy.cn,direct             # 设置 go 下载源为国内源
 $ go get -u github.com/gin-gonic/gin                      # -u 强制使用网络下载安装 Gin 依赖包

 $ go list -m all | grep gin
 > github.com/gin-gonic/gin v1.9.1
 $ go mod init web                                         # 初始化 web 项目
 $ touch main.go                                           # 创建项目入口文件
 $ go get -u github.com/gin-gonic/gin                      # 安装 gin 框架

 $ ls -l
 total 24
 > -rw-r--r-- 1 root root  2265 Jul 19 02:45 go.mod
 > -rw-r--r-- 1 root root 15259 Jul 19 02:45 go.sum
 > -rw-r--r-- 1 root root   234 Jul 19 03:18 main.go

编辑 main.go 文件,添加代码

package main

import (
    "github.com/gin-gonic/gin"                             // 引入 gin
    "net/http"
)

func main() {
    engine := gin.Default()                                // 实例化 engine 对象
    engine.GET("/", webRoot)                               // 注册路由 / 及其处理函数
    engine.GET("/index", webIndex)                         // 注册路由 /index 及其处理函数
    engine.Run(":8080")                                    // 启动服务, 监听 8080 端口
}

func webRoot(context *gin.Context) {
    context.String(http.StatusOK, "this is root page")
}

func webIndex(context *gin.Context) {
    context.String(http.StatusOK, "this is index page")
}

执行 main.go

 $ go run main.go
 > ......
 > [GIN-debug] GET    /                         --> main.webRoot (3 handlers)
 > [GIN-debug] GET    /index                    --> main.webIndex (3 handlers)
 > ......
 > [GIN-debug] Listening and serving HTTP on :8080

Github 个人主页 http://github.com/{username}, 替换不同用户名即可进入不同用户的 Github 主页 网址中的 username 就是路由参数, 后台服务拿到 username 的实际值然后返回该用户的信息

Gin 通过 Param() 或 Params 获取路由中的参数

func (c *Context) Param(key string) string                 // Param 返回 string 类型

type Params []Param
func (ps Params) ByName(name string) (va string)           // Params 的参数查找方法
func (ps Params) Get(name string) (string, bool)           // Params 的参数查找方法
func main() {
    ...
    engine.GET("/index/:id", routeParam)                   // 注册路由和对应函数
    engine.GET("/group/:name", routeParams)
    ...
}

func routeParam(c *gin.Context) {                          // index 任意子界面
    id := c.Param("id")                                    // Param 获取路由参数的值
    c.String(200, "id: %s", id)
}

func routeParams(c *gin.Context) {                         // group 任意子界面
    n, err := c.Params.Get("name")                         // Params.Get 获取路由参数值
    m := c.Params.ByName("name")                           // Params.ByName 获取路由参数值
    c.String(200, "n: %s  m: %s", n, m)
}

网址 https://github.com/facsert?tab=repositories? 后的便是 Quary 参数, 参数形式 key=value, 通过 & 分隔

Gin 通过以下方法获取 query 参数

func (c *Context) GetQuery(key string) (string, bool)
func (c *Context) Query(key string) string
func (c *Context) DefaultQuery(key, defaultValue string) string

func (c *Context) GetQueryArray(key string) ([]string, bool)
func (c *Context) QueryArray(key string) []string
func main() {
    ...
    engine.GET("/index/", routeQuerys)                     // 注册路由和对应函数
    engine.GET("/group/", routeQuery)
    ...
}

func routeQuerys(c *gin.Context) {                         // http://localhost:8080/index?id=4
    id := c.QueryArry("id")                                // 获取 queray 参数值列表
    c.String(200, "id: %v", id)                            // id: [4]
}

func routeQuery(c *gin.Context) {                          // http://localhost:8080/group?name=jack
    n, err := c.DefaultQuery("name", "nobody")             // 未获取到则使用默认值 nobody
    m := c.Query("name")                                   // query 获取参数值
    c.String(200, "n: %s  m: %s", n, m)                    // n: jack  m: jack
}

Form 表单数据存储在 POST 请求体中, 请求体格式: application/x-www-form-urlencoded

func (c *Context) PostForm(key string) string
func (c *Context) DefaultPostForm(key, defaultValue string) stri
func (c *Context) GetPostForm(key string) (string, bool)
func (c *Context) PostFormMap(key string) map[string]string


func (c *Context) PostFormArray(key string) []string
func (c *Context) GetPostFormArray(key string) ([]string, bool)
func (c *Context) GetPostFormMap(key string) (map[string]string, bool)
func main() {
    ...
    engine.POST("/table/", table)                          // 注册路由和对应函数
    ...
}

func table(c *gin.Context) {                               // curl -X 'POST' http://localhost:8080/table
    name := c.PostForm("name")                             // -H 'Content-Type: application/x-www-form-urlencoded'
    age := c.PostForm("age")                               // -d 'name=lily&age=16'
    c.String(200, "name:%s age:%s", name, age)             // name:lily age:16
}

JSON 数据存储在 POST 请求体中, 请求体 application/json, 获取原始数据后格式化转 map

func main() {
    ...
    engine.POST("/raw/", rawData)                          // 注册路由和对应函数
    ...
}

func rawData(c *gin.Context) {                             // curl -X 'POST' http://localhost:8080/raw
    data, _ := c.GetRawData()                              // -H 'Content-Type: application/json'
    var m map[string]any                                   // -d '{name:lily, age:16}'
    _ = json.Unmarshal(data, &m)
    c.String(200, "Json: %#v", m)                          // Json: map[string]interface {}{"age":"14", "user":"petter"}
}

基于请求类型开发接口比较麻烦, 且多种参数都是 key-value 形式, 于是有了自适应解析 定义一个结构体, 将请求体字段与结构体属性绑定, 通过 ShouldBind 赋值给结构体属性

type Person struct {                                       // 结构体属性开头大写, 允许外部使用
    Name string `json:"name" form:"name" binding:"required"`
    Age  string `json:"age" form:"age" binding:"required"`
}

func main() {
    engine := gin.Default()
    engine.POST("/model", func(c *gin.Context) {           // Body {"age": "16","name": "lily"}
        var p Person
        err := c.ShouldBind(&p)                            // 自适应解析
        if err != nil { c.String(400, "login fail") }
        c.String(200, "login info: %#v", p)               // login info: main.Person{Name:"Bob", Age:"16"}
    })
}