导读
本套笔记是为了学习过其他语言框架,想要快速掌握gin框架推行的一套笔记。 虽然为了青训营而制作的一套笔记,但其他想要学go的程序员也可以通过这个上手go世界,后续会带你快速上手gorm,学完这两个之后,简体版抖音基本上就可以独立完成了,后续还会进行大项目的讲解开发,制作不易,喜欢的就点个关注吧。
注意
代码详解大部分是注释的形式给出,请留意代码注释。
Gin框架介绍
导读:Gin是一个非常受欢迎的Golang Web框架,它旨在提供高性能、易用和轻量级的解决方案。
中间件
中间件(Middleware)是在应用程序处理请求和生成响应之间执行的一系列功能组件。它请求到达目标处理程序之前或响应回传给客户端之前,对请求和响应进行预处理或后处理。类似java的拦截器。
大白话:Gin框架允许开发者在处理请求的过程中,加入用户自己的钩子(Hook)函数,这个钩子函数就叫中间件。
在 Gin 框架中,gin.HandlerFunc 是一个具有特定签名的函数类型,它接受一个 *gin.Context 参数,并没有返回值。这个函数类型被用作中间件函数和路由处理函数的类型,Gin中的中间件必须是一个gin.HandlerFunc类型。
单独注册中间件
package main
import (
"fmt"
"github.com/gin-gonic/gin"
"net/http"
)
func get(c *gin.Context) {
fmt.Println("get运行了")
c.JSON(http.StatusOK, gin.H{
"msg": "ok",
})
}
//定义一个中间件
func m1(c *gin.Context) {
fmt.Println("中间件运行了")
}
func main() {
router := gin.Default()
router.GET("/get", m1, get)
router.Run(":8080")
}
当我们运行之后,发送send,会执行m1,之后执行get。
postman接收到信息
多个中间件
router.GET,后面可以跟很多HandlerFunc方法,这些方法其实都可以叫中间件
package main
import (
"fmt"
"github.com/gin-gonic/gin"
"net/http"
)
func get(c *gin.Context) {
fmt.Println("get运行了")
c.JSON(http.StatusOK, gin.H{
"msg": "ok",
})
}
// 定义一个中间件
func m1(c *gin.Context) {
fmt.Println("m1运行了")
}
func m2(c *gin.Context) {
fmt.Println("m2运行了")
}
func main() {
router := gin.Default()
router.GET("/get", m1, get,m2)
router.Run(":8080")
}
运行结果如下
先运行m1,之后运行get,最后运行m2,以此类推,也可以增加更多的中间件
中间件拦截响应
只需要修改m1
// 定义一个中间件
func m1(c *gin.Context) {
fmt.Println("m1运行了")
//用于终止请求的处理流程并立即返回响应
c.Abort()
}
运行结果
可以看到只有m1运行了
中间件放行
使用c.next()进行放行,会直接运行下一个方法,下一个方法运行结束之后运行c.next()之后的方法
修改代码
func get(c *gin.Context) {
fmt.Println("get运行了")
c.JSON(http.StatusOK, gin.H{
"msg": "ok",
})
c.Next()
fmt.Println("get再次运行")
}
// 定义一个中间件
func m1(c *gin.Context) {
fmt.Println("m1运行了")
c.Next()
fmt.Println("m1再次运行")
}
func m2(c *gin.Context) {
fmt.Println("m2运行了")
c.Next()
fmt.Println("m2再次运行")
}
运行结果如图
注意:如果其中一个中间件响应了c.Abort(),后续中间件将不再执行,直接按照顺序走完所有的响应中间件
全局注册中间件
在 Gin 框架中,Use 方法用于将中间件函数注册到全局中间件链中。全局中间件会在每个请求处理之前都被执行,无论请求的路径是什么。使用Use去注册全局中间件,Use接收的参数也是多个HandlerFunc
package main
import (
"fmt"
"github.com/gin-gonic/gin"
"net/http"
)
func get(c *gin.Context) {
fmt.Println("get运行了")
c.JSON(http.StatusOK, gin.H{
"msg": "ok",
})
c.Next()
fmt.Println("get再次运行")
}
func m10(c *gin.Context) {
fmt.Println("m10运行了")
}
func main() {
router := gin.Default()
router.Use(m10)
router.GET("/get", get)
router.POST("/post", get)
router.Run(":8080")
}
我们使用get和post分别发送请求,m10都会先运行。
中间件传递数据
我们使用c.Get()和c.Set()方法来传递数据
c.Set() 是 Gin 框架中的方法,用于在请求处理过程中设置键值对数据。
c.Get() 是 Gin 框架中的方法,用于获取在请求处理过程中设置的键值对数据。
package main
import (
"fmt"
"github.com/gin-gonic/gin"
"net/http"
)
func get(c *gin.Context) {
name, _ := c.Get("name")//获得数据
fmt.Println(name)
c.JSON(http.StatusOK, gin.H{
"msg": "ok",
})
c.Next()
}
func m10(c *gin.Context) {
fmt.Println("m10运行了")
c.Set("name", "xiaoming") //定义一个数据
}
func main() {
router := gin.Default()
router.Use(m10)
router.GET("/get", get)
router.Run(":8080")
}
运行结果
可以看到成功拿到了数据name
Set()第二个参数是any类型,所有我们可以用它传任意类型,在接收的时候做好断言即可
例如一个结构体
package main
import (
"fmt"
"github.com/gin-gonic/gin"
"net/http"
)
type User struct {
Name string
Age int
} //定义user结构体
func get(c *gin.Context) {
name, _ := c.Get("user") //获得结构退
fmt.Println(name)//打印结构体
c.JSON(http.StatusOK, gin.H{
"msg": "ok",
})//响应信息
c.Next()
}
func m10(c *gin.Context) {
fmt.Println("m10运行了")
c.Set("user", User{
Name: "xiaoming",
Age: 18,
}) 构造结构体user
}
func main() {
router := gin.Default()
router.Use(m10)
router.GET("/get", get)
router.Run(":8080")
}
运行结果
路由
路由分组
将一系列的路由放到一个组下,统一管理
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
func get(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"msg": "ok",
})
}
func main() {
router := gin.Default()
r := router.Group("/group") //分组
r.GET("/get", get)
r.POST("/post", get)
router.Run(":8080")
}
这样在postman里面我们如果要发送请求,只需要这样
两个响应的结果都是一样的
路由分组注册中间件
就是在分组后面加上Use就可以了
package main
import (
"fmt"
"github.com/gin-gonic/gin"
"net/http"
)
func middle(c *gin.Context) {
fmt.Println("middle ...in")
}
func get(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"msg": "ok",
})
}
func main() {
router := gin.Default()
r := router.Group("/group").Use(middle) //分组并且使用全局中间件
r.GET("/get", get)
r.POST("/post", get)
router.Run(":8080")
}
分别发送请求之后
权限验证
以前后端最流行的jwt为例,如果用户登录了,前端发来的每一次请求都会在请求头上携带上token
后台拿到这个token进行校验,验证是否过期,是否非法
如果通过就说明这个用户是登录过的
不通过就说明用户没有登录
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
//验证jwt令牌是否正确的方法
//每次都要验证
func JwtTokenMiddleware(c *gin.Context) {
// 获取请求头的token
token := c.GetHeader("token")
// 调用jwt的验证函数
if token == "1234" {
// 验证通过
c.Next()
return
}
// 验证不通过
c.JSON(200, gin.H{"msg": "权限验证失败"})
c.Abort()
}
func get(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"msg": "ok",
})
}
func main() {
router := gin.Default()
r := router.Group("/group").Use(JwtTokenMiddleware)
r.GET("/get", get)
r.POST("/post", get)
router.Run(":8080")
}
我们使用postman发送请求
1: 如果token != 1234
2: 如果token = 1234