这是我参与「第三届青训营 -后端场」笔记创作活动的的第4篇笔记。基于上课所讲内容,查阅官方文档,通过b站课程进行了简单的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 参数方法:Query、DefaultQuery
匹配的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 参数方法:PostForm、DefaultPostForm
可以通过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)
什么是中间件?
- 在请求达到路由的方法的前和后进行的一系列操作(洋葱模型)
如何使用中间件?
- 在路由组上进行
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()
}
}