开发者

Golang中Gin框架的使用入门教程

目录
  • 安装与简单测试
  • 常见请求与分组请求
  • 获取参数 与 参数合法性验证
    • 获得query中参数
    • 获得multipart/urlencoded form中的参数
    • 模型绑定和参数验证
    • 自定义参数验证
  • 项目结构参考
    • Gin框架运行模式
      • Gin如何获取客户ip
        • Gin处理请求结果
          • 以String类型响应请求
          • 以json格式响应请求
          • 以文件形式响应请求
          • 设置http响应头
          • Gin处理html模板
          • Gin访问静态资源文件
        • Gin处理Cookie操作
          • Gin文件上传
            • Gin中间件

              官方地址:gin-gonic.com/docs/

              安装与简单测试

              下载并安装Gin包,并导入引用

              $ go get -u github.com/gin-gonic/gin
              
              //将gin引入到代码中
              import "github.com/gin-gonic/gin"
              //可选。如果使用诸如 http.StatusOK 之类的常量,则需要引入 net/http 包
              import "net/http"
              

              编写如下测试代码

              package main
              
              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() // 监听并在 0.0.0.0:8080 上启动服务
              }
              

              然后在浏览器中进行测试: http://localhost:8080 就可以访问到响应的请求。

              常见请求与分组请求

              下面展示几种其他 常规 请求方式

              // 下面列出常用几种请求方式
              r.GET("/someGet", handle)
              r.POST("/somePost", handle)
              r.PUT("/somePut", handle)
              r.DELETE("/someDelete", handle)
              r.PATCH("/somePatch", handle)
              r.HEAD("/someHead", handle)
              r.OPTIONS("/someOptions", handle)
              r.Any("/any", handle)
              

              **还可以对请求进行分组操作nCVkYrt。 **

              v1 := r.Group("/v1")
              {
                 v1.GET("/login", handle)
              }
              v2 := r.Group("/v2")
              {
                 v2.GET("/login", handle)
              }
              

              下面例子 是** 获得请求中path**

              func main() {
                 router := gin.Default()
              
                 // 匹配/user/john
                 router.GET("/user/:name", func(c *gin.Context) {
                    name := c.Param("name")
                    c.String(http.StatusOK, "Hello %s", name)
                 })
              
                 // 匹配/user/john/和/user/john/send
                 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)
                 })
              
                 router.Run(":8080")
              }
              

              /user/:name/*action : 表示对后边路由全部模糊匹配。例如:/user/john/send/1 形式 action会匹配得到 name 是 john, action是 /send/1

              获取参数 与 参数合法性验证

              获得query中参数

              func main() {
                 router := gin.Default()
              
                 // welcome?firstname=Jane&lastname=Doe
                 router.GET("/user", func(c *gin.Context) {
                    firstname := c.DefaultQuery("name", "kim") // 获取query中的name,没有的话就为kim
              http://www.devze.com      lastname := c.Query("age")                 // 获取query中的age
                    c.String(http.Stat编程usOK, "Hello %s %s", firstname, lastname)
                 })
                 router.Run(":8080")
              }
              

              获得multipart/urlencoded form中的参数

              func main() {
                 router := gin.Default()
                 router.POST("/form_post", func(c *gin.Context) {
                    message := c.PostForm("age")
                    nick := c.DefaultPostForm("name", "kim")
              
                    c.JSON(200, gin.H{
                       "status":  "posted",
                       "message": message,
                       "nick":    nick,
                    })
                 })
                 router.Run(":8080")
              }
              

              curl http://127.0.0.1:8080/form\_post -X POST -d 'name=john&age=25'

              通过此curl发送post请求,即可获得表单中数据。

              模型绑定和参数验证

              基本用法

              我们已经见识了x-www-form-urlencoded类型的参数处理,现在越来越多的应用习惯使用JSON来通信,也就是无论返回的response还是提交的request,其content-type类型都是application/json的格式。而对于一些旧的web表单页还是x-www-form-urlencoded的形式,这就需要我们的服务器能支持住这多种content-type的参数了。

              由于go是静态语言,需要先实现定义数据模型,这就需要用到gin的model bind功能了。

              gin使用go-playground/validator.v8验证参数,查看完整文档。

              需要在绑定的字段上设置tag,比如,绑定格式为json,需要这样设置json:"fieldname" 。

              此外,Gin还提供了两套绑定方法:

              1.Must bind

              • Methods - Bind, BindJSON, BindXML, BindQuery, BindYAML
              • Behavior - 这些方法底层使用 MustBindwith,如果存在绑定错误,请求将被以下指令中止 .

              c.AbortWithError(400, err).SetType(ErrorTypeBind),

              响应状态代码会被设置为400,请求头Content-Type被设置为text/plain; charset=utf-8。

              注意,如果你试图在此之后设置响应代码,将会发出一个警告 [GIN-debug] [WARNING] Headers were already written. Wanted to override status code 400 with 422,如果你希望更好地控制行为,请使用ShouldBind相关的方法

              2.Should bind

              • Methods - ShouldBind, ShouldBindJSON, ShouldBindXML, ShouldBindQuery, ShouldBindYAML
              • Behavior - 这些方法底层使用 ShouldBindWith,如果存在绑定错误,则返回错误,开发人员可以正确处理请求和错误。

              当我们使用绑定方法时,Gin会根据Content-Type推断出使用哪种绑定器,如果你确定你绑定的是什么,你可以使用MustBindWith或者BindingWith。

              你还可以给字段指定特定规则的修饰符,如果一个字段用binding:"required"修饰,并且在绑定时该字段的值为空,那么将返回一个错误。

              type Person struct {
                 Name string `json:"name" binding:"required"`      // json格式从name取值,并且该值为必须的
                 Age  int    `json:"age" binding:"required,gt=20"` // json格式从age取值,并且该值为必须的,且必须大于20
              }
              开发者_C教程
              func main() {
                 router := gin.Default()
                 router.POST("/test", func(context *gin.Context) {
                    var person Person
                    // 这里我确定传过来的一定是JSON所以用ShouldBindJSON,否则可以用ShouldBind
                    if err := context.ShouldBindJSON(&person); err != nil {
                       context.JSON(http.StatusBadRequest, gin.H{
                          "error": err.Error(),
                       })
                       return
                    }
                    context.JSON(http.StatusOK, gin.H{
                       "success": true,
                    })
                 })
                 router.Run(":8080")
              }
              
              curl http://localhost:8080/test -X POST -d '{"name":"Rock","age": 25}'
              

              上面是通过json映射方式 绑定 请求数据,并且对请求数据进行验证。

              自定义参数验证

              验证包 gopkg.in/go-playground/validator.v8使用方法

              package main
              
              import (
                 "net/http"
                 "reflect"
                 "time"
              
                 "github.com/gin-gonic/gin"
                 "github.com/gin-gonic/gin/binding"
                 "gopkg.in/go-playground/validator.v8"
              )
              
              type Booking struct {
                 // 这里的验证方法为bookabledate
                 CheckIn time.Time `form:"check_in" binding:"required,bookabledate" time_format:"2006-01-02"`
                 // gtfield=CheckIn表示大于的字段为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是一个reflect.Type的接口类型变量,通过Interface方法获得field接口类型变量的真实类型,可以理解为reflect.Value的逆操作
                 // 在这里,断言就是将一个接口类型的变量转化为time.Time,前提是后者必须实现了前者的接口
                 // 综上,这里就是将field进行了类型转换
                 if date, ok := field.Interface().(time.Time); ok {
                    today := time.Now()
                    if today.Year() > date.Year() || today.YearDay() > date.YearDay() {
                       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(":8080")
              }
              
              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()})
                 }
              }
              

              上面方法自定义了一种参数验证器。

              项目结构参考

              ├── conf #项目配置文件目录 │ └── config.toml #大家可以选择自己熟悉的配置文件管理工具包例如:toml、xml等等 ├── controllers #控制器目录,按模块存放控制器(或者叫控制器函数),必要的时候可以继续划分子目录。 │ ├── food.go │ └── user.go ├── main.go #项目入口,这里负责Gin框架的初始化,注册路由信息,关联控制器函数等。 ├── models #模型目录,负责项目的数据存储部分,例如各个模块的mysql表的读写模型。 │ ├── food.go │ └── user.go ├── static #静态资源目录,包括Js,css,jpg等等,可以通过Gin框架配置,直接让用户访问。 │ ├── css │ ├── images │ └── js ├── logs #日志文件目录,主要保存项目运行过程中产生的日志。 └── views #视图模板目录,存放各个模块的视图模板,当然有些项目只有api,是不需要视图部分,可以忽略这个目录 └── index.html

              Gin框架运行模式

              为方便调试,Gin 框架在运行的时候默认是debug模式,在控制台默认会打印出很多调试日志,上线的时候我们需要关闭debug模式,改为release模式。

              设置Gin框架运行模式:

              通过环境变量设置 export GIN_MODE=release

              GIN_MODE环境变量,可以设置为debug或者release

              通过代码设置

              在main函数,初始化gin框架的时候执行下面代码
              // 设置 release模式
              gin.SetMode(gin.ReleaseMode)
              // 或者 设置debug模式
              gin.SetMode(gin.DebugMode)
              

              Gin如何获取客户ip

              route.GET("/ip", func(c *gin.Context) {
                 // 获取用户IP
                 ip := c.ClientIP()
                 c.JSON(http.StatusBadRequest, gin.H{"ip": ip})
              })
              

              Gin处理请求结果

              以String类型响应请求

              func (c *Context) String(code int, format string, values ...interface{})
              c.String(200,"欢迎访问%s, 你是%s", "tizi360.com!","最靓的仔!")
              

              以Json格式响应请求

              我们开发api接口的时候常用的格式就是json,下面是返回json格式数据的例子

              // User 定义
              type User struct {
                Name  string `json:"name"` // 通过json标签定义struct字段转换成json字段的名字。www.devze.com
                Email string `json:"email"`
              }
              
              // Handler 控制器
              func(c *gin.Context) {
                //初始化user对象
                u := &User{
                  Name:  "tizi365",
                  Email: "tizi@tizi365.com",
                }
                //返回json数据
                //返回结果:{"name":"tizi365", "email":"tizi@tizi365.com"}
                c.JSON(200, u)
              }
              

              以文件形式响应请求

                c.FileAttachment("/var/www/1.jpg", "1.jpg")
              

              设置http响应头

              func(c *gin.Context) {
                //设置http响应 header, key/value方式,支持设置多个header
                c.Header("site","tizi365")
              }
              

              Gin处理html模板

              func main() {
                  // 初始化gin对象
                  router := gin.Default()
                  // 首先加载templates目录下面的所有模版文件,模版文件扩展名随意
                  router.LoadHTMLGlob("templates/*")
                  // 绑定一个url路由 /index
                  router.GET("/index", func(c *gin.Context) {
                          // 通过HTML函数返回html代码
                          // 第二个参数是模版文件名字
                          // 第三个参数是map类型,代表模版参数
                          // gin.H 是map[string]interface{}类型的别名
                          c.HTML(http.StatusOK, "index.html", gin.H{
                                  "title": "Main website",
                          })
                  })
                  // 启动http服务,并且绑定在8080端口
                  router.Run(":8080")
              }
              

              Gin访问静态资源文件

              func main() {
                  router := gin.Default()
                  // 设置静态资源文件目录,并且绑定一个Url前缀
                  // 静态资源文件目录:/var/www/tizi365/assets
                  // /assets是访问静态资源的url前缀
                  // 例如:
                  //   /assets/images/1.jpg 这个url文件,存储在/var/www/tizi365/assets/images/1.jpg
                  router.Static("/assets", "/var/www/tizi365/assets")
              
                  // 为单个静态资源文件,绑定url
                  // 这里的意思就是将/favicon.ico这个url,绑定到./resources/favicon.ico这个文件php
                  router.StaticFile("/favicon.ico", "./resources/favicon.ico")
              
                  // Listen and serve on 0.0.0.0:8080
                  router.Run(":8080")
              }
              

              Gin处理Cookie操作

              package main
              
              import (
                 "fmt"
                 "github.com/gin-gonic/gin"
              )
              
              func main() {
                 router := gin.Default()
                 // 设置cookie路由
                 router.GET("/setCookie", func(c *gin.Context) {
                    // 设置cookie
                    c.SetCookie("site_cookie", "cookievalue", 3600, "/", "localhost", false, true)
                 })
                 // 获得cookie路由
                 router.GET("/cookie", func(c *gin.Context) {
                    data, err := c.Cookie("/cookie")
                    fmt.Printf(data)
                    if err != nil {
                       // 直接返回cookie值
                       c.String(200, data)
                       return
                    }
                    c.String(200, "not found!")
                 })
                 //删除cookie路由
                 router.GET("/removeCookie", func(c *gin.Context) {
                    c.SetCookie("set_cookie", "cookievalue", -1, "/", "localhost", false, true)
                    c.String(200, "删除cookie")
                 })
                 router.Run(":8080")
              }
              

              Gin文件上传

              package main
              
              // 导入gin包
              import (
                 "fmt"
                 "github.com/gin-gonic/gin"
                 "log"
                 "net/http"
              )
              
              func main() {
                 router := gin.Default()
                 // 设置文件上传大小限制,默认是32m
                 router.MaxMultipartMemory = 64 << 20 // 64 MiB
              
                 router.POST("/upload", func(c *gin.Context) {
                    // 获取上传文件,返回的是multipart.FileHeader对象,代表一个文件,里面包含了文件名之类的详细信息
                    // file是表单字段名字
                    file, _ := c.FormFile("file")
                    // 打印上传的文件名
                    log.Println(file.Filename)
              
                    // 将上传的文件,保存到./data/1111.jpg 文件中
                    c.SaveUploadedFile(file, "./data/1111.jpg")
              
                    c.String(http.StatusOK, fmt.Sprintf("'%s' uploaded!", file.Filename))
                 })
                 router.Run(":8080")
              }
              

              Gin中间件

              在Gin框架中,中间件(Middleware)指的是可以拦截http请求-响应生命周期的特殊函数,在请求-响应生命周期中可以注册多个中间件,每个中间件执行不同的功能,一个中间执行完再轮到下一个中间件执行。

              中间件的常见应用场景如下:

              • 请求限速
              • api接口签名处理
              • 权限校验
              • 统一错误处理

              Gin支持设置全局中间件和针对路由分组设置中间件,设置全局中间件意思就是会拦截所有请求,针对分组路由设置中间件,意思就是仅对这个分组下的路由起作用。

               package main
              
              // 导入gin包
              import (
                 "fmt"
                 "github.com/gin-gonic/gin"
                 "log"
                 "time"
              )
              
              // 自定义个日志中间件
              func Logger() gin.HandlerFunc {
                 return func(c *gin.Context) {
                    t := time.Now()
              
                    // 可以通过上下文对象,设置一些依附在上下文对象里面的键/值数据
                    c.Set("example", "12345")
                    fmt.Printf("1. 执行中间件设置 \n")
                    // 在这里处理请求到达控制器函数之前的逻辑
              
                    // 调用下一个中间件,或者控制器处理函数,具体得看注册了多少个中间件。
                    c.Next()
                    fmt.Printf("4. 完成 执行中间件设置 \n")
                    // 在这里可以处理请求返回给用户之前的逻辑
                    latency := time.Since(t)
                    log.Print(latency)
              
                    // 例如,查询请求状态吗
                    status := c.Writer.Status()
                    log.Println(status)
                 }
              }
              
              func main() {
                 r := gin.New()
                 // 注册上面自定义的日志中间件
                 r.Use(Logger())
              
                 r.GET("/test", func(c *gin.Context) {
                    // 查询我们之前在日志中间件,注入的键值数据
                    fmt.Printf("2. 开始执行业务逻辑 \n")
                    example := c.MustGet("example").(string)
              
                    // it would print: "12345"
                    log.Println(example)
                    fmt.Printf("3. 业务逻辑执行完成 \n")
                 })
              
                 // Listen and serve on 0.0.0.0:8080
                 r.Run(":8080")
              }
              

              其输出结果如下:

              1. 执行中间件设置 

              2. 开始执行业务逻辑 

              2022/10/22 16:33:29 12345

              3. 业务逻辑执行完成 

              4. 完成 执行中间件设置 

              2022/10/22 16:33:29 658.681µs

              2022/10/22 16:33:29 200

              Gin 中间件类似 Node中的洋葱模型。

              以上就是golang中Gin框架的使用入门教程的详细内容,更多关于Golang Gin框架的资料请关注我们其它相关文章!

              0

              上一篇:

              下一篇:

              精彩评论

              暂无评论...
              验证码 换一张
              取 消

              最新开发

              开发排行榜