深入理解 Go 語言 Gin 框架的請求處理機制

一、獲取 GET 請求

1、URL?參數

package main
import (
  "github.com/gin-gonic/gin"
  "net/http"
)
func main() {
  //Default返回一個默認的路由引擎
  r := gin.Default()
  r.GET("/user/search", func(c *gin.Context) {
    username := c.DefaultQuery("username", "snail")
    //username := c.Query("username")
    address := c.Query("address")
    //輸出json結果給調用方
    c.JSON(http.StatusOK, gin.H{
      "message":  "ok",
      "username": username,
      "address":  address,
    })
  })
  r.Run()
}

2、url 中 path 參數

package main
import (
  "github.com/gin-gonic/gin"
  "net/http"
  "strings"
)
func main() {
  r := gin.Default()
  r.GET("/user/:name/*action", func(c *gin.Context) {
    name := c.Param("name")
    action := c.Param("action")
    //截取/
    action = strings.Trim(action, "/")
    c.String(http.StatusOK, name+" blog: "+action)
  })
  //默認爲監聽8080端口
  r.Run(":8000")
}

二、獲取 form 參數

1、main.go

package main
import (
  "fmt"
  "github.com/gin-gonic/gin"
  "net/http"
)
func main() {
  r := gin.Default()
  r.POST("/form", func(c *gin.Context) {
    types := c.DefaultPostForm("type", "post")
    username := c.PostForm("username")
    password := c.PostForm("userpassword")
    // c.String(http.StatusOK, fmt.Sprintf("username:%s,password:%s,type:%s", username, password, types))
    c.String(http.StatusOK, fmt.Sprintf("username:%s,password:%s,type:%s", username, password, types))
  })
  r.Run()
}

2、form.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta >
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
<form action="http://localhost:8080/form" method="post" action="application/x-www-form-urlencoded">
    用戶名:<input type="text" >  <br>
    密   碼:<input type="password" >  <br>
    <input type="submit" value="提交">
</form>
</body>
</html>

3、演示效果

三、獲取 json 參數

1、獲取 json 參數

package main
import (
  "encoding/json"
  "github.com/gin-gonic/gin"
  "net/http"
)
func main() {
  //Default返回一個默認的路由引擎
  r := gin.Default()
  r.POST("/json", func(c *gin.Context) {
    // 注意:下面爲了舉例子方便,暫時忽略了錯誤處理
    b, _ := c.GetRawData()  // 從c.Request.Body讀取請求數據
    // 定義map或結構體
    var m map[string]interface{}
    // 反序列化
    _ = json.Unmarshal(b, &m)
    c.JSON(http.StatusOK, m)
  })
  r.Run()
}

2、postman 測試

四、ShouldBind 參數綁定

package main
import (
  "fmt"
  "github.com/gin-gonic/gin"
  "net/http"
)
// Binding from JSON
type Login struct {
  User     string `form:"user" json:"user" binding:"required"`
  Password string `form:"password" json:"password" binding:"required"`
}
func main() {
  router := gin.Default()
  // 綁定JSON的示例 ({"user": "zhangsan", "password": "123456"})
  router.POST("/loginJSON", func(c *gin.Context) {
    var login Login
    if err := c.ShouldBind(&login); err == nil {
      fmt.Printf("login info:%#v\n", login)
      c.JSON(http.StatusOK, gin.H{
        "user":     login.User,
        "password": login.Password,
      })
    } else {
      c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
    }
  })
  // 綁定form表單示例 (user=zhangsan&password=123456)
  router.POST("/loginForm", func(c *gin.Context) {
    var login Login
    // ShouldBind()會根據請求的Content-Type自行選擇綁定器
    if err := c.ShouldBind(&login); err == nil {
      c.JSON(http.StatusOK, gin.H{
        "user":     login.User,
        "password": login.Password,
      })
    } else {
      c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
    }
  })
  // 綁定QueryString示例 (/loginForm?user=zhangsan&password=123456)
  router.GET("/loginForm", func(c *gin.Context) {
    var login Login
    // ShouldBind()會根據請求的Content-Type自行選擇綁定器
    if err := c.ShouldBind(&login); err == nil {
      c.JSON(http.StatusOK, gin.H{
        "user":     login.User,
        "password": login.Password,
      })
    } else {
      c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
    }
  })
  // Listen and serve on 0.0.0.0:8080
  router.Run(":8080")
}

五、獲取單個文件

1、main.go

package main
import (
    "github.com/gin-gonic/gin"
)
func main() {
    r := gin.Default()
    //限制上傳最大尺寸
    r.MaxMultipartMemory = 8 << 20
    r.POST("/upload", func(c *gin.Context) {
        file, err := c.FormFile("file")
        if err != nil {
            c.String(500, "上傳圖片出錯")
        }
        // c.JSON(200, gin.H{"message": file.Header.Context})
        c.SaveUploadedFile(file, file.Filename)
        c.String(http.StatusOK, file.Filename)
    })
    r.Run()
}

2、upload.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta >
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <form action="http://localhost:8080/upload" method="post" enctype="multipart/form-data">
          上傳文件:<input type="file"  >
          <input type="submit" value="提交">
    </form>
</body>
</html>

3、上傳特定文件

package main
import (
    "fmt"
    "log"
    "net/http"
    "github.com/gin-gonic/gin"
)
func main() {
    r := gin.Default()
    r.POST("/upload", func(c *gin.Context) {
        _, headers, err := c.Request.FormFile("file")
        if err != nil {
            log.Printf("Error when try to get file: %v", err)
        }
        //headers.Size 獲取文件大小
        if headers.Size > 1024*1024*2 {
            fmt.Println("文件太大了")
            return
        }
        //headers.Header.Get("Content-Type")獲取上傳文件的類型
        if headers.Header.Get("Content-Type") != "image/png" {
            fmt.Println("只允許上傳png圖片")
            return
        }
        c.SaveUploadedFile(headers, "./video/"+headers.Filename)
        c.String(http.StatusOK, headers.Filname)
    })
    r.Run()
}

六、獲取多個文件

1、main.go

package main
import (
   "github.com/gin-gonic/gin"
   "net/http"
   "fmt"
)
// gin的helloWorld
func main() {
   // 1.創建路由
   // 默認使用了2箇中間件Logger(), Recovery()
   r := gin.Default()
   // 限制表單上傳大小 8MB,默認爲32MB
   r.MaxMultipartMemory = 8 << 20
   r.POST("/upload", func(c *gin.Context) {
      form, err := c.MultipartForm()
      if err != nil {
         c.String(http.StatusBadRequest, fmt.Sprintf("get err %s", err.Error()))
      }
      // 獲取所有圖片
      files := form.File["files"]
      // 遍歷所有圖片
      for _, file := range files {
         // 逐個存
         if err := c.SaveUploadedFile(file, file.Filename); err != nil {
            c.String(http.StatusBadRequest, fmt.Sprintf("upload err %s", err.Error()))
            return
         }
      }
      c.String(200, fmt.Sprintf("upload ok %d files", len(files)))
   })
   //默認端口號是8080
   r.Run(":8000")
}

2、upload.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta >
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <form action="http://localhost:8000/upload" method="post" enctype="multipart/form-data">
          上傳文件:<input type="file"  multiple>
          <input type="submit" value="提交">
    </form>
</body>
</html>
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/AzfCL5Uy283H1ltedlgdsw