GO_Gin

前言

  Gin是一个用Go(Golang)编写的轻量级HTTP web框架,以其运行速度快、API友好和封装优雅著称。Gin框架支持RESTful风格的API设计,允许开发者使用URL定位资源,并通过HTTP请求类型(如GET、POST、PUT、DELETE等)描述操作。

框架介绍

  • 安装引入

    • 安装
      go get -u github.com/gin-gonic/gin
      
      引入
      import "github.com/gin-gonic/gin"
      
      示例:
      package main
      import "github.com/gin-gonic/gin"
      func main() {
        router := gin.Default()
        router.GET("/ping", func(c *gin.Context) {
          c.JSON(200, gin.H{
            "message": "pong",
          })
        })
        router.Run() // 监听并在 0.0.0.0:8080 上启动服务
      }
  • 路由

    • 普通路由

      • router.GET("/", func)
        router.POST("/login", func)
        router.Any("/login", func)
    • 路由分组

      •   v1 := router.Group("/v1")
            {
                group1.GET("/user", func(c *gin.Context) {
                    c.String(200, "v1 hello world")
                })
            }
        
            group2 := router.Group("/v2")
            {
                group2.GET("/user", func(c *gin.Context) {
                    c.String(200, "v2 hello world")
                })
            }
    • restful

      •     router.GET("/user", QueryFunc)    //查询
            router.Post("/user", AddFunc)    // 新增
            router.Delete("/user", DeleteFunc)    // 删除
            router.PUT("/user", UpdateFunc)    // 更新(客户端提供完整数据)
            router.PATCH("/user", PatchUpdateFunc)    // 更新(客户端提供需要修改的数据)
        }
    • 重定向

      • router.GET("/test", func(c *gin.Context) {
            c.Redirect(http.StatusMovedPermanently, "http://www.google.com/")
        })
            
    • 静态文件

      • //静态文件
        router.Static("/static", "./static")
        //router.StaticFS("/static", http.Dir("static"))
        router.StaticFile("/f1", "./static/1.txt") // 单独的文件

 

  • 输出

    • JSON

      • func outputfunc(r *gin.Engine) {
            r.GET("/user", func(c *gin.Context) {
                //JSON
                user := &User{
                    Name:     "111",
                    Password: "123456",
                }
                c.JSON(200, user)
                
                //c.JSON(200, gin.H{
                //    "message": "success",
                //    "code":    200,
                //})
            })
        }
        结果
        {"Name":"111","Password":"123456"}
    • XML

      • func outputfunc(r *gin.Engine) {
            r.GET("/user", func(c *gin.Context) {
                //JSON
                user := &User{
                    Name:     "111",
                    Password: "123456",
                }
               c.XML(200, user)
            })
        }
        
        结果
        <User>
            <Name>111</Name>
            <Password>123456</Password>
        </User>
    • HTML

      • c.HTML(200, "user.impl", gin.H{
                    "title": "HTML 测试",
                })
        结果:
        HTML 测试

        注意:有子目录时, 注意.impl文件的定义
        templates/posts/index.tmpl
        {{ define "posts/index.tmpl" }}
        <html><h1>
          {{ .title }}
        </h1>
        </html>
        {{ end }}
  • 参数

    • 非绑定获取

      • URL:127.0.0.1:8080/user/111/222
      • router.GET("/user/:n/:p", func(c *gin.Context) {
                name := c.Param("n")
                passwd := c.Param("p")
                c.JSON(200, gin.H{
                    "name":     name,
                    "password": passwd,
                })
            })
      • URL:127.0.0.1:8080/user?n=1&p=2

      • router.GET("/user", func(c *gin.Context) {
                name := c.Query("n")
                passwd := c.Query("p")
                c.JSON(200, gin.H{
                    "name":     name,
                    "password": passwd,
                })
            })

        URL:127.0.0.1:8080/userForm

      • router.POST("/userForm", func(c *gin.Context) {
                name := c.PostForm("n")
                passwd := c.PostForm("p")
                c.JSON(200, gin.H{
                    "name":     name,
                    "password": passwd,
                })
            })
    • 参数绑定

      • ShouldBind: 自动识别参数,并绑定对应字段到结构体中
        
        ShouldBindJSON    tag:json
        ShouldBindXML        tag:xml
        ShouldBindQuery    tag:form
        ShouldBindYAML    tag:yaml
        ShouldBindTOML    tag:toml
        ShouldBindHeader    tag:header    无法自动识别
        ShouldBindUri    tag:uri    无法自动识别
        
        type formA struct {
          Foo string `json:"foo" xml:"foo" binding:"required" form:"foo"`
        }

 

  • 模型验证

    • Gin使用 go-playground/validator/v10 进行验证

      • type LoginInfo struct {
            Username string `json:"username" form:"username" binding:"required"`
            Password string `json:"password" form:"password" binding:"number"`
            Email    string `json:"email" form:"email" binding:"email"`
        }
        
        func Validator() {
            r := gin.Default()
        
            r.GET("/", func(c *gin.Context) {
                login := LoginInfo{}
                err := c.ShouldBind(&login)
                if err != nil {
                    c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
                    return
                }
        
                c.JSON(http.StatusOK, login)
            })
        
            err := r.Run(":8080")
            if err != nil {
                panic(err)
            }
        }
    • 自定义验证器

      • import (
          "net/http"
          "reflect"
          "time"
        
          "github.com/gin-gonic/gin"
          "github.com/gin-gonic/gin/binding"
          "github.com/go-playground/validator/v10"
        )
        
        // Booking 包含绑定和验证的数据。
        type Booking struct {
          CheckIn  time.Time `form:"check_in" binding:"required,bookabledate" time_format:"2006-01-02"`
          CheckOut time.Time `form:"check_out" binding:"required,gtfield=CheckIn,bookabledate" time_format:"2006-01-02"`
        }
        
        var bookableDate validator.Func = func(fl validator.FieldLevel) bool {
          date, ok := fl.Field().Interface().(time.Time)
          if ok {
            today := time.Now()
            if today.After(date) {
              return false
            }
          }
          return true
        }
        
        func main() {
          route := gin.Default()
        
          if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
            v.RegisterValidation("bookabledate", bookableDate)
          }
        
          route.GET("/bookable", getBookable)
          route.Run(":8085")
        }
        
        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()})
          }
        }
  • 中间件

    • 调用栈

      • func mw1() gin.HandlerFunc {
            return func(c *gin.Context) {
                fmt.Println("mw1 before")
                c.Next()
                fmt.Println("mw1 after")
            }
        }
        
        func mw2() gin.HandlerFunc {
            return func(c *gin.Context) {
                fmt.Println("mw2 before")
                c.Next()
                fmt.Println("mw2 after")
            }
        }
        
        func Middleware() {
            r := gin.Default()
        
            r.GET("/", mw1(), mw2(), func(c *gin.Context) {
                fmt.Println("self")
                c.String(http.StatusOK, "self")
            })
        
            err := r.Run(":8080")
            if err != nil {
                panic(err)
            }
        }
        
        输出:
        mw1 before
        mw2 before
        self
        mw2 after
        mw1 after
    • 使用中间件

      • func middleFunc(router *gin.Engine) {
            user := router.Group("/user", gin.BasicAuth(gin.Accounts{
                "user": "123456",
            }))
            user.GET("/name", func(c *gin.Context) {
                user := c.MustGet(gin.AuthUserKey).(string)
                c.String(http.StatusOK, user)
            })
        }
  • HTTPS

    • 自有证书

      Openssl 生成证书,如果只是提供API服务,可以用没有经过认证的证书,如果是网站,则需要认证证书

      • router.RunTLS(":8080", "./testdata/server.pem", "./testdata/server.key")
    • 开源免费认证证书(Let's Encrypt)

      • package main
        
        import (
          "log"
        
          "github.com/gin-gonic/autotls"
          "github.com/gin-gonic/gin"
          "golang.org/x/crypto/acme/autocert"
        )
        
        func main() {
          router := gin.Default()
        
          // Ping handler
          router.GET("/ping", func(c *gin.Context) {
            c.String(200, "pong")
          })
        
          m := autocert.Manager{
            Prompt:     autocert.AcceptTOS,
            HostPolicy: autocert.HostWhitelist("example1.com", "example2.com"),
            Cache:      autocert.DirCache("/var/www/.cache"),
          }
        
          log.Fatal(autotls.RunWithManager(r, &m))
        }

         

 

posted @ 2025-11-20 23:45  直至成伤  阅读(4)  评论(0)    收藏  举报