Go框架 - Gin的使用

1,094 阅读4分钟

Gin是什么

用Go语言编写的高性能HTTP框架.

Gin的特性

  1. 快速 - 内存占用小, 没有反射
  2. 支持中间件 - 可以recoverHTTP请求中的panic, 保证服务器始终可用
  3. JSON验证 - 检查所需的值是否存在
  4. 路由组 - 更好的组织API, 并且路由组可以无限嵌套
  5. 错误管理 - 方便收集HTTP请求中的错误, 并写入日志文件
  6. 内置渲染 - 方便对JSON, XML和HTML的渲染
  7. 可扩展性 - 可以很方便的新建一个中间件

Gin的安装使用

  1. 下载并安装Gin

    在终端中键入如下命令

     go get -u github.com/gin-gonic/gin
    
  2. 将Gin引入到工程中

     import (
     • "github.com/gin-gonic/gin"
       "net/http"
     )
    
  3. 如果要使用Go语言中定义的状态码, 要引入"net/http"包, 否则不必

    例如

     http.StatusOK // 就代表200这个常量
    

    下面只是列出"net/http"这个包下的一部分常量定义

     StatusOK                   = 200 // RFC 7231, 6.3.1
     StatusCreated              = 201 // RFC 7231, 6.3.2
     StatusAccepted             = 202 // RFC 7231, 6.3.3
     StatusNonAuthoritativeInfo = 203 // RFC 7231, 6.3.4
     StatusNoContent            = 204 // RFC 7231, 6.3.5
     StatusResetContent         = 205 // RFC 7231, 6.3.6
     StatusPartialContent       = 206 // RFC 7233, 4.1
     StatusMultiStatus          = 207 // RFC 4918, 11.1
     StatusAlreadyReported      = 208 // RFC 5842, 7.1
     StatusIMUsed               = 226 // RFC 3229, 10.4.1
    

Gin的简单使用

   // 初始化一个Gin路由
   r := gin.Default()
   
   // 进行/gin_use的URL注册
   r.GET("/gin_use", func(c *gin.Context) {
     c.JSON(http.StatusOK, gin.H{
       "code": 200,
       "msg": "/gin_use请求成功",
     })
   })
   
   /*
   让Gin进行HTTP请求监听服务
   默认端口号: 8080
   本机ip地址: 127.0.0.1 / localhost
   */
   r.Run()

Gin支持的请求方式

GET, POST, PUT, DELETE, HEAD, PATCH, OPTIONS

GET请求中的数据获取

Query & DefaultQuery

 r.GET("/user_login", func(c *gin.Context) {
   // 查询指定的请求参数,如果没有, 则设置一个默认值
    username := c.DefaultQuery("username", "shaosiming")
   
   // 查询指定的请求参数
    password := c.Query("password")
    c.JSON(200, gin.H{
       "username":username,
       "password":password,
    })
 })

ShouldBind

   // 定义一个接收数据的结构体
   type LoginData struct {
     Username string `form:"username" binding:"required"`
     Password string `form:"password" binding:"required"`
   }
   
   r.GET("/login", func(context *gin.Context) {
     // 声明一个接收数据的结构体变量
     var loginData LoginData
 ​
     // 显式声明绑定方式
     //err := context.ShouldBindWith(&loginData, binding.Form)
 ​
     // 通过一个结构体类型变量来接收数据, 自动绑定
     err := context.ShouldBind(&loginData)
     if err != nil {
       fmt.Println(err)
     } else {
       // 在这里进行登录逻辑的判断
       // 返回一个json格式的数据
       context.JSON(200, gin.H{
         "username":loginData.Username,
         "password":loginData.Password,
         "msg":"请求成功",
       })
     }
   })

BindUri

 // 定义一个结构体, 用来进行Uri的绑定
 type Person struct {
   Name string `uri:"name" binding:"required"`
   Age int `uri:"age" binding:"required"`
 }
 ​
 r.GET("/bindUri/:name/:age", func(c *gin.Context) {
    var person Person
    err := c.BindUri(&person)
    if err != nil {
       c.JSON(400, err.Error())
    } else {
       c.JSON(200, &person)
    }
 })

POST请求中的数据获取

PostForm & DefaultPostForm

   r.POST("form_post", func(c *gin.Context) {
     // 通过指定key从form中取出数据
     message := c.PostForm("message")
 ​
     // 如果form中没有这个key, 则设置一个默认值
     nick := c.DefaultPostForm("nick", "shaosiming")
     c.JSON(200, gin.H{
       "message":message,
       "nick":nick,
       "msg":"发送成功",
     })
   })

ShouldBindJSON

 r.POST("/bindJSON", func(c *gin.Context) {
    var user LoginData
   // 请求体为JSON格式的数据, 将其绑定到对应的结构体变量上
    err := c.ShouldBindJSON(&user)
    if  err == nil {
       c.JSON(200, &user)
    } else {
       c.JSON(400, err.Error())
    }
 })

响应的数据格式

JSON

 r.GET("/somejson", func(c *gin.Context) {
    c.JSON(200, gin.H{
       "code":0,
       "msg":"json请求成功",
    })
 })

struct

 // struct
 r.GET("/struct", func(c *gin.Context) {
   // 定义一个结构体变量
    var user struct{
       Name string
       Age int
    }
    user.Name = "shaosiming"
    user.Age = 18
 ​
    // 也可以将结构体类型的变量当作返回类型
    c.JSON(200, &user)
 })

XML

 r.GET("/someXML", func(c *gin.Context) {
   // 将一个map转换为xml格式进行返回
    c.XML(200, gin.H{
       "code":0,
       "msg":"xml请求成功",
    })
 })

单个文件的上传

 r.POST("/single_upload", func(c *gin.Context) {
    // 单个文件的上传
    file, err := c.FormFile("file")
    if err != nil {
       fmt.Println(err)
    } else {
       fmt.Println(file.Filename)
       // 保存到文件目录
       dst := "./" + file.Filename
       c.SaveUploadedFile(file, dst)
       c.JSON(200, gin.H{
          "code":0,
          "msg":file.Filename + "上传成功",
       })
    }
 })

可以使用curl进行测试

curl -X POST http://localhost:8080/single_upload -F "file=@/Users/Shaosiming/Desktop/test.png" -H "Content-Type: multipart/form-data"

多个文件的上传

 r.POST("/multi_upload", func(c *gin.Context) {
    form, _ := c.MultipartForm()
 ​
    // 获取多个文件
    files := form.File["upload[]"]
 ​
    // 将多个文件保存到指定目录
    for _, file := range files {
       log.Println(file.Filename)
       dst := "./" + file.Filename;
       c.SaveUploadedFile(file, dst)
    }
    c.JSON(200, gin.H{
       "code":0,
       "msg":"多个文件上传成功",
    })
 })

可以使用curl进行测试

curl -X POST http://localhost:8080/multi_upload -F "upload[]=@/Users/Shaosiming/Desktop/test1.png" -F "upload[]=@/Users/Shaosiming/Desktop/test2.png" -H "Content-Type: multipart/form-data"

路由组的使用

注意: 路由组是可以无限嵌套的哦

 // 路由组的使用
 v1 := r.Group("/v1")
 {
    v1.GET("/login", func(c *gin.Context) {
       c.JSON(200, gin.H{
          "version":1.0,
          "msg":"login请求成功",
       })
    })
    v1.GET("/update", func(c *gin.Context) {
       c.JSON(200, gin.H{
          "version":1.0,
          "msg":"update请求成功",
       })
    })
 }
 ​
 v2 := r.Group("/v2")
 {
    v2.GET("/login", func(c *gin.Context) {
       c.JSON(200, gin.H{
          "version":2.0,
          "msg":"login请求成功",
       })
    })
    v2.GET("/update", func(c *gin.Context) {
       c.JSON(200, gin.H{
          "version":2.0,
          "msg":"update请求成功",
       })
    })
 }

重定向

 // 外部重定向
 r.GET("goto_baidu", func(c *gin.Context) {
    c.Redirect(301, "https://www.baidu.com/")
 })
 ​
 // 内部重定向
 r.GET("/redirect2", func(c *gin.Context) {
    c.Redirect(301, "/redirect3")
 })
 ​
 r.GET("/redirect3", func(c *gin.Context) {
    c.JSON(200, "direct3")
 })
 ​
 // 路由重定向
 r.GET("/redirect4", func(c *gin.Context) {
    c.Request.URL.Path = "/redirect5"
    r.HandleContext(c)
 })
 ​
 r.GET("/redirect5", func(c *gin.Context) {
    c.JSON(200, "direct5")
 })