go-gin快速入门(2)

1.中间件

  • 全局中间件(所有请求都经过此中间件)
    • 关键字 Use(自定义func)
    • 自定义func 需要返回gin.HandleFunc
    • 可以使用Set 设置key,value. 使用Get 获取值
package main

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"net/http"
	"time"
)

func main() {
	r := gin.Default()
	r.Use(Name())
	r.GET("/test1", func(c *gin.Context) {
		value, _ := c.Get("request")  // 获取值
		c.JSON(http.StatusOK, gin.H{
			"message": "success",
			"data":    value})
	})
	r.Run(":8080")
}

func Name() gin.HandlerFunc {
	return func(c *gin.Context) {
		t := time.Now()
		fmt.Println("中间件被执行了.")
		c.Set("request", "value")  // 设置值
		status := c.Writer.Status()
		fmt.Println("执行状态", status)
		t2 := time.Since(t)
		fmt.Println("耗时", t2)
	}
}

测试代码:

import httpx  # httpx第三方库和requests类似,https://www.python-httpx.org/quickstart/
one = httpx.get("http://0.0.0.0:8080/test1")
one.json()
{'data': 'value', 'message': 'success'}
  • 局部中间件 和Next() / Abort()

    • Next 让程序继续执行,Abort 终止执行
    • 在指定func前添加 中间件,只对其产生作用
    func main() {
    	// 创建路由
    	r := gin.New()
    	r.Use(MyLogger())
    	goodsGroup := r.Group("/goods")
    	{
    		goodsGroup.GET("/test1", func1)
    		goodsGroup.POST("/test2", tokenRequired(), func2)
    	}
    	_ = r.Run(":8081")
    }
    
    func MyLogger() gin.HandlerFunc {
    	return func(c *gin.Context) {
    		start := time.Now()
    		c.Set("name", "zap")
    		//给request中的header设置X-Token
    		c.Request.Header.Set("X-Token", "123")
    		//让原来的逻辑继续执行
    		c.Next()
    		end := time.Since(start)
    		fmt.Println("耗时:", end)
    		status := c.Writer.Status()
    		log.Println(status)
    	}
    }
    
    func func2(context *gin.Context) {
    	v, ok := context.Get("name")
    	if !ok {
    		fmt.Println("name不存在")
    	}
    	context.JSON(http.StatusOK, gin.H{
    		"code": 200, "data": v})
    }
    
    func func1(context *gin.Context) {
    	v, ok := context.Get("name")
    	if !ok {
    		fmt.Println("设置的name不存在, ")
    	}
    	context.JSON(http.StatusOK, gin.H{
    		"code": v})
    }
    
    func tokenRequired() gin.HandlerFunc {
    	return func(c *gin.Context) {
    		var token string
    		for k, v := range c.Request.Header {
    			fmt.Printf("key:%s, value:%v, type:%T\n", k, v, v)
    			// key:X-Token, value:[123], type:[]string
    			if k == "X-Token" {
    				token = v[0]
    			}
    		}
    
    		if token != "123" {
    			c.JSON(http.StatusUnauthorized, gin.H{
    				"mse": "未登录",
    			})
    			c.Abort() // 结束执行
    		}
    		// 继续执行后面的逻辑
    		c.Next()
    		fmt.Println("中间件执行完毕.")
    	}
    }
    

    测试代码:

    httpx.get("http://0.0.0.0:8081/goods/test1").text
    httpx.post("http://0.0.0.0:8081/goods/test2").text
    

2.cookie练习

func AuthMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		// 获取客户端cookie并校验
		if cookie, err := c.Cookie("abc"); err == nil {
			if cookie == "123" {
				fmt.Println("cookie 验证 通过, cookie:", cookie)
				return
			}
		}
		// 否则就是没通过
		c.JSON(http.StatusUnauthorized, gin.H{
			"err": "验证失败",
		})
		//验证失败则不用在调用后续的函数处理
		c.Abort()
		return
	}
}

func main() {
	r := gin.Default()
	r.GET("/login", func(c *gin.Context) {
		//设置cookie
		c.SetCookie("abc", "123", 60, "/", "localhost", false, true)

		c.JSON(http.StatusOK, gin.H{"msg": "success"})
	})

	r.GET("/home", AuthMiddleware(), func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{"msg": "success", "data": "home"})
	})

	_ = r.Run(":8080")
}

3. 自定义参数验证

  • 参考 https://pkg.go.dev/github.com/go-playground/validator/v10#FieldLevel

  • 关键点:自定义func, 注册func

    package main
    
    import (
    	"fmt"
    	"github.com/gin-gonic/gin"
    	"github.com/gin-gonic/gin/binding"
    	"github.com/go-playground/validator/v10"
    	"net/http"
    )
    
    type User struct {
    	Name string `json:"name" binding:"required,NotAdmin"`
    }
    
    func NotAdmin(fl validator.FieldLevel) bool {
    	fmt.Println("验证方法")                    // 1.先调试 验证进入此方法了
    	fmt.Println("fl.Field():", fl.Field()) // FieldLevel是一个接口,在此接口实现的方法,其中Field返回字段值
    	// fl.Field 返回值是反射类型,不能直接比较,就转字符串比较
    	if fl.Field().Interface().(string) != "admin" {
    		return false
    	}
    	return true
    }
    
    func main() {
    	r := gin.Default()
    	if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
    		// 注册自定义验证规则,两则名称可以不一致,tag 在struct中使用
    		v.RegisterValidation("NotAdmin", NotAdmin)
    	}
    	r.POST("/1", func(c *gin.Context) {
    		var user User
    		if e := c.BindJSON(&user); e == nil {
    			fmt.Println(user) // 调试代码
    			c.JSON(http.StatusOK, gin.H{"msg": "success"})
    		} else {
    			c.JSON(http.StatusBadRequest, gin.H{"msg": "参数错误"})
    		}
    	})
    	r.Run(":9999")
    }
    

    测试代码:

    httpx.post("http://0.0.0.0:9999/1", json={"name":"admin1"}).json()
    {'msg': '参数错误'}
    httpx.post("http://0.0.0.0:9999/1", json={"name":"admin"}).json()
    {'msg': 'success'}
    
posted @ 2021-10-25 14:26  CV-coding  阅读(52)  评论(0)    收藏  举报