全局中间件

全局中间件表示,所有的请求都经过该函数

```go package main

import ( “fmt” “github.com/gin-gonic/gin” “time” )

//中间件 func MiddleWare() gin.HandlerFunc { return func(c *gin.Context) { //获取当前时间 now := time.Now() fmt.Println(“开始执行中间件函数”) c.Set(“request”, “中间件”) status := c.Writer.Status() fmt.Println(“中间件执行完成======>”, status) t2 := time.Since(now) fmt.Println(“time:”, t2) } }

func main() { r := gin.Default() //注册中间件 r.Use(MiddleWare()) r.GET(“/middle”, func(context *gin.Context) { req, _ := context.Get(“request”) context.JSON(200, gin.H{“request”: req}) }) r.Run() } curl http://127.0.0.1:8080/middle 控制台输出 开始执行中间件函数 中间件执行完成======> 200 C:\Users\dell>curl http://127.0.0.1:8080/middle {“request”:”中间件”}

  1. <a name="11d4f518"></a>
  2. #### Next()方法
  3. > ```go
  4. package main
  5. import (
  6. "fmt"
  7. "github.com/gin-gonic/gin"
  8. "time"
  9. )
  10. //中间件
  11. func MiddleWare() gin.HandlerFunc {
  12. return func(c *gin.Context) {
  13. //获取当前时间
  14. now := time.Now()
  15. fmt.Println("开始执行中间件函数")
  16. c.Set("request", "中间件")
  17. //执行完函数
  18. c.Next()
  19. fmt.Println("函数执行完成")
  20. //执行完函数之后再执行
  21. status := c.Writer.Status()
  22. fmt.Println("中间件执行完成======>", status)
  23. t2 := time.Since(now)
  24. fmt.Println("time:", t2)
  25. }
  26. }
  27. func main() {
  28. r := gin.Default()
  29. //注册中间件
  30. r.Use(MiddleWare())
  31. r.GET("/middle", func(context *gin.Context) {
  32. req, _ := context.Get("request")
  33. context.JSON(200, gin.H{"request": req})
  34. })
  35. r.Run()
  36. }

局部中间件

```go package main

import ( “fmt” “github.com/gin-gonic/gin” “time” )

//局部中间件 func MiddleWare() gin.HandlerFunc { return func(c *gin.Context) { //获取当前时间 now := time.Now() fmt.Println(“开始执行中间件函数”) c.Set(“request”, “中间件”) //执行完函数 c.Next() fmt.Println(“函数执行完成”) //执行完函数之后再执行 status := c.Writer.Status() fmt.Println(“中间件执行完成======>”, status) t2 := time.Since(now) fmt.Println(“time:”, t2) } }

func main() { r := gin.Default() //局部中间件 r.GET(“/middle”,MiddleWare(), func(context *gin.Context) { req, _ := context.Get(“request”) context.JSON(200, gin.H{“request”: req}) }) r.Run() }

  1. > 关于常用中间件分享<br />
  2. [中间件推荐](https://hub.fastgit.org/gin-gonic/contrib/blob/master/README.md)
  3. <a name="69832669"></a>
  4. #### 会话控制
  5. > 1. Cookie介绍
  6. > 1. HTTP是无状态协议,服务器不能记录浏览器的访问状态,也就是说服务器不能区分两次请求是否由同一个客户端发出
  7. > 2. Cookie就是解决HTTP协议无状态的方案之一
  8. > 3. Cookie实际上就是服务器保存在浏览器的一段信息
  9. > 4. Cookie由服务器创建,并发送给浏览器,最终由浏览器保存
  10. > ```go
  11. package main
  12. import (
  13. "fmt"
  14. "github.com/gin-gonic/gin"
  15. )
  16. func main() {
  17. // 1.创建路由
  18. // 默认使用了2个中间件Logger(), Recovery()
  19. r := gin.Default()
  20. // 服务端要给客户端cookie
  21. r.GET("cookie", func(c *gin.Context) {
  22. // 获取客户端是否携带cookie
  23. cookie, err := c.Cookie("key_cookie")
  24. if err != nil {
  25. cookie = "NotSet"
  26. // 给客户端设置cookie
  27. // maxAge int, 单位为秒
  28. // path,cookie所在目录
  29. // domain string,域名
  30. // secure 是否智能通过https访问
  31. // httpOnly bool 是否允许别人通过js获取自己的cookie
  32. c.SetCookie("key_cookie", "value_cookie", 60, "/",
  33. "localhost", false, true)
  34. }
  35. fmt.Printf("cookie的值是: %s\n", cookie)
  36. })
  37. r.Run(":8000")
  38. }

Sessions

gorilla/sessions为自定义session后端提供cookie和文件系统session以及基础结构。

主要功能是:

  • 简单的API:将其用作设置签名cookie的简便方法
  • 内置的后端可将session存储在cookie或文件系统中
  • Flash消息:一直持续读取session值
  • 切换session持久化和设置其他属性的便捷方法
  • 旋转身份验证和加密密钥的机制
  • 每个请求有多个session,即使使用不同的后端也是如此
  • 自定义session后端的接口和基础结构:可以使用通用API检索并批量保存来自不同商店的session。

```go package main

import ( “fmt” “github.com/gorilla/sessions” “net/http” )

//初始化一个cookie存储对象 //bzka是一个自己的密钥 var store = sessions.NewCookieStore([]byte(“bzka”))

func main() { http.HandleFunc(“/save”, SaveSession) http.HandleFunc(“/get”, GetSession) err := http.ListenAndServe(“:8080”, nil) if err != nil { fmt.Println(“HTTP server failed,err:”, err) return } }

func SaveSession(w http.ResponseWriter, r http.Request) { // 获取一个session对象,session-name是session的名字 session, err := store.Get(r, “sessionName”) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } // 在session中存储值 session.Values[“foo”] = “bar” session.Values[42] = 43 // 保存更改 session.Save(r, w) } func GetSession(w http.ResponseWriter, r http.Request) { session, err := store.Get(r, “sessionName”) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } foo := session.Values[“foo”] fmt.Println(foo) }

  1. <a name="186ffcaf"></a>
  2. #### 参数验证
  3. > 用gin框架的数据验证,可以不勇解析数据,减少if else会简洁许多
  4. > ```go
  5. package main
  6. import (
  7. "fmt"
  8. "time"
  9. "github.com/gin-gonic/gin"
  10. )
  11. //Person ..
  12. type Person struct {
  13. //不能为空并且大于10
  14. Age int `form:"age" binding:"required,gt=10"`
  15. Name string `form:"name" binding:"required"`
  16. Birthday time.Time `form:"birthday" time_format:"2006-01-02" time_utc:"1"`
  17. }
  18. func main() {
  19. r := gin.Default()
  20. r.GET("/5lmh", func(c *gin.Context) {
  21. var person Person
  22. if err := c.ShouldBind(&person); err != nil {
  23. c.String(500, fmt.Sprint(err))
  24. return
  25. }
  26. c.String(200, fmt.Sprintf("%#v", person))
  27. })
  28. r.Run()
  29. }
  30. //请求
  31. http://localhost:8080/5lmh?age=8&name=枯藤&birthday=2006-01-02
  32. result
  33. Key: 'Person.Age' Error:Field validation for 'Age' failed on the 'gt' tag

自定义验证

```go package main

import ( “github.com/gin-gonic/gin” “github.com/gin-gonic/gin/binding” “github.com/go-playground/validator/v10” “net/http” “time” )

//Person .. type Person struct { //不能为空并且大于10 Age int form:"age" binding:"required,gt=10" Name string form:"name" binding:"NotNullAndAdmin" Birthday time.Time form:"birthday" time_format:"2006-01-02" time_utc:"1" }

//官方示例https://pkg.go.dev/gopkg.in/go-playground/validator.v8?utm_source=godoc#hdr-Custom_Functions //自定义验证函数 //v8框架如下写法 //func nameNotNullAndRoot(v *validator.Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { // if value, ok := field.Interface().(string); ok { // // 字段不能为空,并且不等于 admin // return value != “” && !(“root” == value) // } // return true //}

//v8以上框架写法 func nameNotNullAndRoot(fl validator.FieldLevel) bool { name := fl.Field().Interface().(string) return name != “” && !(“root” == name) } func main() { r := gin.Default() //自定义的校验方法注册到validator中 if v, ok := binding.Validator.Engine().(validator.Validate); ok { // 这里的 key 和 fn 可以不一样最终在 struct 使用的是 key v.RegisterValidation(“NotNullAndAdmin”, nameNotNullAndRoot) } r.GET(“/name”, func(context gin.Context) { var person Person if e := context.ShouldBind(&person); e == nil { context.String(http.StatusOK, “%v”, person) } else { context.String(http.StatusOK, “person bind err:%v”, e.Error()) } }) r.Run() } person bind err:Key: ‘Person.Name’ Error:Field validation for ‘Name’ failed on the ‘NotNullAndAdmin’ tag

package main

import ( “net/http” “reflect” “time”

“github.com/gin-gonic/gin” “github.com/gin-gonic/gin/binding” “gopkg.in/go-playground/validator.v8” )

// Booking contains binded and validated data. type Booking struct { //定义一个预约的时间大于今天的时间 CheckIn time.Time form:"check_in" binding:"required,bookabledate" time_format:"2006-01-02" //gtfield=CheckIn退出的时间大于预约的时间 CheckOut time.Time form:"check_out" binding:"required,gtfield=CheckIn" time_format:"2006-01-02" }

func bookableDate( v *validator.Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string, ) bool { //field.Interface().(time.Time)获取参数值并且转换为时间格式 if date, ok := field.Interface().(time.Time); ok { today := time.Now() if today.Unix() > date.Unix() { return false } } return true }

func main() { route := gin.Default() //注册验证 if v, ok := binding.Validator.Engine().(*validator.Validate); ok { //绑定第一个参数是验证的函数第二个参数是自定义的验证函数 v.RegisterValidation(“bookabledate”, bookableDate) }

route.GET(“/5lmh”, getBookable) route.Run() }

func getBookable(c *gin.Context) { var b Booking if err := c.ShouldBindWith(&b, binding.Query); err == nil { c.JSON(http.StatusOK, gin.H{“message”: “Booking dates are valid!”}) } else { c.JSON(http.StatusBadRequest, gin.H{“error”: err.Error()}) } }

// curl -X GET “http://localhost:8080/5lmh?check_in=2019-11-07&check_out=2019-11-20“ // curl -X GET “http://localhost:8080/5lmh?check_in=2019-09-07&check_out=2019-11-20“ // curl -X GET “http://localhost:8080/5lmh?check_in=2019-11-07&check_out=2019-11-01

  1. <a name="820c26d4"></a>
  2. #### 多语言翻译验证
  3. > 对于多业务系统可能存在特殊需求,手机端需要中文而PC端需要英文,有的则包含自定义信息
  4. > ```go
  5. package main
  6. import (
  7. "github.com/gin-gonic/gin"
  8. "github.com/gin-gonic/gin/binding"
  9. "github.com/go-playground/locales/zh"
  10. ut "github.com/go-playground/universal-translator"
  11. "github.com/go-playground/validator/v10"
  12. en_translations "github.com/go-playground/validator/v10/translations/en"
  13. )
  14. var (
  15. uni *ut.UniversalTranslator
  16. validate *validator.Validate
  17. trans ut.Translator
  18. )
  19. type Person struct {
  20. //不能为空并且大于10
  21. Age int `form:"age" binding:"required,gt=10"`
  22. }
  23. func Init() {
  24. //注册翻译器
  25. zh := zh.New()
  26. uni = ut.New(zh, zh)
  27. trans, _ = uni.GetTranslator("zh")
  28. //获取gin的校验器
  29. validate := binding.Validator.Engine().(*validator.Validate)
  30. //中文版本
  31. //zh_translations.RegisterDefaultTranslations(validate, trans)
  32. //英文版本
  33. en_translations.RegisterDefaultTranslations(validate, trans)
  34. }
  35. //Translate 翻译错误信息
  36. func Translate(err error) map[string][]string {
  37. var result = make(map[string][]string)
  38. errors := err.(validator.ValidationErrors)
  39. for _, err := range errors {
  40. result[err.Field()] = append(result[err.Field()], err.Translate(trans))
  41. }
  42. return result
  43. }
  44. func main() {
  45. //初始化注册器
  46. Init()
  47. r := gin.Default()
  48. r.GET("zhV", func(context *gin.Context) {
  49. var person Person
  50. if err := context.ShouldBind(&person); err == nil {
  51. context.JSON(200, gin.H{"message": "Success"})
  52. } else {
  53. context.JSON(500, gin.H{"message": Translate(err)})
  54. }
  55. })
  56. r.Run()
  57. }
  58. http://localhost:8080/zhV
  59. {
  60. "message": {
  61. "Age": [
  62. "Age为必填字段"
  63. ]
  64. }
  65. }