gin入门知识点 | 青训营笔记

323 阅读3分钟

这是我参与「第三届青训营 -后端场」笔记创作活动的的第4篇笔记。基于上课所讲内容,查阅官方文档,通过b站课程进行了简单的gin框架学习以进行抖音项目开发。

参考视频:go圈里最会写js的奇淼 - gin 教程

参考文档:

一个简单的hello,gin程序:

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

func main() {
	r := gin.Default()
	r.GET("/ping", func(c *gin.Context) {
		c.JSON(200, gin.H{
			"message": "pong",
		})
	})
	r.Run(":8090") // 修改端口号, 默认8080
}

浏览器访问:http://localhost:8090/ping,得到以下响应:

{ "success":true, }

各种请求方式获取参数

获取 URI 中的参数:Param

第一种,此规则能够匹配 /user/john 这种格式,但不能匹配 /user/ 或 /user 这种格式

第二种,此规则既能匹配 /user/john/ 格式也能匹配 /user/john/send 这种格式 如果没有其他路由器匹配 /user/john,它将重定向到 /user/john/

// 此规则能够匹配 /user/john 这种格式,但不能匹配 /user/ 或 /user 这种格式
router.GET("/user/:name", func(c *gin.Context) {
  name := c.Param("name")
  c.String(http.StatusOK, "Hello %s", name)
})

// 此规则既能匹配 /user/john/ 格式也能匹配 /user/john/send 这种格式
// 如果没有其他路由器匹配 /user/john,它将重定向到 /user/john/
router.GET("/user/:name/*action", func(c *gin.Context) {
  name := c.Param("name")
  action := c.Param("action")
  message := name + " is " + action
  c.String(http.StatusOK, message)
})


获取 Get 参数方法:QueryDefaultQuery

匹配的url格式: /welcome?firstname=Jane&lastname=Doe

// 匹配的url格式: /welcome?firstname=Jane&lastname=Doe
router.GET("/welcome", func(c *gin.Context) {
  firstname := c.DefaultQuery("firstname", "Guest") // 设置默认值
  lastname := c.Query("lastname")

  c.String(http.StatusOK, "Hello %s %s", firstname, lastname)
})

获取 Post 参数方法:PostFormDefaultPostForm

可以通过DefaultPostForm()设置默认值

router.POST("/form_post", func(c *gin.Context) {
  message := c.PostForm("message")
  nick := c.DefaultPostForm("nick", "anonymous") // 此方法可以设置默认值

  c.JSON(200, gin.H{
    "status":  "posted",
    "message": message,
    "nick":    nick,
  })
})

绑定参数和参数验证

文档:模型绑定和验证

Gin 提供了 MustBind 和 ShouldBind 两类绑定方法,推荐使用 ShouldBind 

绑定json

type Login struct {
	User     string `form:"user" json:"user" xml:"user"  binding:"required"`
	Password string `form:"password" json:"password" xml:"password" binding:"required"`
}

func main() {
	router := gin.Default()
	router.POST("/loginJSON", func(c *gin.Context) {
		var json Login
		if err := c.ShouldBindJSON(&json); err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
			return
		}
		
		if json.User != "manu" || json.Password != "123" {
			c.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized"})
			return
		} 
		
		c.JSON(http.StatusOK, gin.H{"status": "you are logged in"})
	})

文件的上传和返回

文档:

读取文件

读取单个文件

import (
	"io"
	"os"

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

func main() {
	router := gin.Default()
	router.POST("/upload", func(c *gin.Context) {
		file, _ := c.FormFile("file")
		name := c.PostForm("name") // 获取其他数据
	
    // 将文件写到本地
		in, _ := file.Open()
		defer in.Close()
		out, _ := os.Create("./" + file.Filename)
		defer out.Close()
		io.Copy(out, in)

		c.JSON(200, gin.H{
			"file": file,
			"name": name,
		})
	})
	router.Run(":8080")
}

可以使用 Gin 提供的保存文件到指定位置

file, _ := c.FormFile("file")
c.SaveUploadedFile(file, "./"+file.Filename) // 保存文件到指定位置

给前端返回文件

func main() {
	router := gin.Default()
	router.POST("/upload", func(c *gin.Context) {
		file, _ := c.FormFile("file")

		// 保存文件到本地
		c.SaveUploadedFile(file, "./"+file.Filename)

		// 将文件返给前端
		c.Writer.Header().Add("Content-Disposition",
			fmt.Sprintf("attachment; filename=%s", file.Filename))
		c.File("./" + file.Filename)
	})
	router.Run(":8080")
}

中间件和路由分组

路由组 | Gin Web Framework (gin-gonic.com)

分组

什么是分组

  • 对 router 创建 Group 就是分组,同一分组会拥有同一前缀和同一中间件

如何创建路由组

router := gin.Default()

// 简单的路由组: v1
v1 := router.Group("/v1")
{
  v1.POST("/login", loginEndpoint)
  v1.POST("/submit", submitEndpoint)
  v1.POST("/read", readEndpoint)
}

// 简单的路由组: v2
v2 := router.Group("/v2")
{
  v2.POST("/login", loginEndpoint)
  v2.POST("/submit", submitEndpoint)
  v2.POST("/read", readEndpoint)
}

中间件

使用中间件 | Gin Web Framework (gin-gonic.com)

自定义中间件 | Gin Web Framework (gin-gonic.com)

什么是中间件

  • 在请求达到路由的方法的前和后进行的一系列操作(洋葱模型)

image.png 如何使用中间件

  • 在路由组上进行 use 操作,后面传入中间件函数即可

如何创建中间件

func Logger() gin.HandlerFunc {
	return func(c *gin.Context) {
		t := time.Now()

		// 设置 example 变量
		c.Set("example", "12345")

		// 请求前
		c.Next()

		// 请求后
		latency := time.Since(t)
		log.Print(latency)

		// 获取发送的 status
		status := c.Writer.Status()
	}
}