GO常用web框架之gin学习笔记(2)| 青训营笔记

103 阅读4分钟

[ go 与 golang | 青训营笔记]

这是我参与「第五届青训营 」伴学笔记创作活动的第 9 天, 在学习了go的相关基础知识以后,可以说是初步的了解了go,接下来,我们将步入全新的环节,今天我们学习go的一个常用web框架gin

4. 请求方式

原始参数 GetRawData

form-data

x-www-form-urlencoded

json

{
    "name": "枫枫",
    "age": 21
}
func _raw(c *gin.Context) {
  body, _ := c.GetRawData()
  contentType := c.GetHeader("Content-Type")
  switch contentType {
  case "application/json":
  
    // json解析到结构体
    type User struct {
      Name string `json:"name"`
      Age  int    `json:"age"`
    }
    var user User
    err := json.Unmarshal(body, &user)
    if err != nil {
      fmt.Println(err.Error())
    }
    fmt.Println(user)
  }
}

封装一个解析json到结构体上的函数

func bindJson(c *gin.Context, obj any) (err error) {
  body, _ := c.GetRawData()
  contentType := c.GetHeader("Content-Type")
  switch contentType {
  case "application/json":
    err = json.Unmarshal(body, &obj)
    if err != nil {
      fmt.Println(err.Error())
      return err
    }
  }
  return nil
}

四大请求方式

GET` `POST` `PUT` `DELETE

Restful风格指的是网络应用中就是资源定位和资源操作的风格。不是标准也不是协议。

GET:从服务器取出资源(一项或多项)

POST:在服务器新建一个资源

PUT:在服务器更新资源(客户端提供完整资源数据)

PATCH:在服务器更新资源(客户端提供需要修改的资源数据)

DELETE:从服务器删除资源

// 以文字资源为例

// GET    /articles          文章列表
// GET    /articles/:id      文章详情
// POST   /articles          添加文章
// PUT    /articles/:id      修改某一篇文章
// DELETE /articles/:id      删除某一篇文章

package main

import (
  "encoding/json"
  "fmt"
  "github.com/gin-gonic/gin"
)

type ArticleModel struct {
  Title   string `json:"title"`
  Content string `json:"content"`
}

type Response struct {
  Code int    `json:"code"`
  Data any    `json:"data"`
  Msg  string `json:"msg"`
}

func _bindJson(c *gin.Context, obj any) (err error) {
  body, _ := c.GetRawData()
  contentType := c.GetHeader("Content-Type")
  switch contentType {
  case "application/json":
    err = json.Unmarshal(body, &obj)
    if err != nil {
      fmt.Println(err.Error())
      return err
    }
  }
  return nil
}

// _getList 文章列表页面
func _getList(c *gin.Context) {
  // 包含搜索,分页
  articleList := []ArticleModel{
    {"Go语言入门", "这篇文章是《Go语言入门》"},
    {"python语言入门", "这篇文章是《python语言入门》"},
    {"JavaScript语言入门", "这篇文章是《JavaScript语言入门》"},
  }
  c.JSON(200, Response{0, articleList, "成功"})
}

// _getDetail 文章详情
func _getDetail(c *gin.Context) {
  // 获取param中的id
  fmt.Println(c.Param("id"))
  article := ArticleModel{
    "Go语言入门", "这篇文章是《Go语言入门》",
  }
  c.JSON(200, Response{0, article, "成功"})
}

// _create 创建文章
func _create(c *gin.Context) {
  // 接收前端传递来的json数据
  var article ArticleModel

  err := _bindJson(c, &article)
  if err != nil {
    fmt.Println(err)
    return
  }

  c.JSON(200, Response{0, article, "添加成功"})
}

// _update 编辑文章
func _update(c *gin.Context) {
  fmt.Println(c.Param("id"))
  var article ArticleModel
  err := _bindJson(c, &article)
  if err != nil {
    fmt.Println(err)
    return
  }
  c.JSON(200, Response{0, article, "修改成功"})
}

// _delete 删除文章
func _delete(c *gin.Context) {
  fmt.Println(c.Param("id"))
  c.JSON(200, Response{0, map[string]string{}, "删除成功"})
}

func main() {
  router := gin.Default()
  router.GET("/articles", _getList)       // 文章列表
  router.GET("/articles/:id", _getDetail) // 文章详情
  router.POST("/articles", _create)       // 添加文章
  router.PUT("/articles/:id", _update)    // 编辑文章
  router.DELETE("/articles/:id", _delete) // 删除文章
  router.Run(":80")
}

请求头相关

请求头参数获取

GetHeader,可以大小写不分,且返回切片中的第一个数据

router.GET("/", func(c *gin.Context) {
  // 首字母大小写不区分  单词与单词之间用 - 连接
  // 用于获取一个请求头
  fmt.Println(c.GetHeader("User-Agent"))
  //fmt.Println(c.GetHeader("user-agent"))
  //fmt.Println(c.GetHeader("user-Agent"))
  //fmt.Println(c.GetHeader("user-AGent"))

  // Header 是一个普通的 map[string][]string
  fmt.Println(c.Request.Header)
  // 如果是使用 Get方法或者是 .GetHeader,那么可以不用区分大小写,并且返回第一个value
  fmt.Println(c.Request.Header.Get("User-Agent"))
  fmt.Println(c.Request.Header["User-Agent"])
  // 如果是用map的取值方式,请注意大小写问题
  fmt.Println(c.Request.Header["user-agent"])

  // 自定义的请求头,用Get方法也是免大小写
  fmt.Println(c.Request.Header.Get("Token"))
  fmt.Println(c.Request.Header.Get("token"))
  c.JSON(200, gin.H{"msg": "成功"})
})

响应头相关

设置响应头

// 设置响应头
router.GET("/res", func(c *gin.Context) {
  c.Header("Token", "jhgeu%hsg845jUIF83jh")
  c.Header("Content-Type", "application/text; charset=utf-8")
  c.JSON(0, gin.H{"data": "看看响应头"})
})

5. 绑定

gin中的bind可以很方便的将 前端传递 来的数据与 结构体 进行 参数绑定 ,以及参数校验

参数绑定

在使用这个功能的时候,需要给结构体加上Tag json form uri xml yaml

Must Bind

不用,校验失败会改状态码

Should Bind

可以绑定json,query,param,yaml,xml

如果校验不通过会返回错误

ShouldBindJSON

package main

import "github.com/gin-gonic/gin"

type UserInfo struct {
  Name string `json:"name"`
  Age  int    `json:"age"`
  Sex  string `json:"sex"`
}

func main() {
  router := gin.Default()
  router.POST("/", func(c *gin.Context) {

    var userInfo UserInfo
    err := c.ShouldBindJSON(&userInfo)
    if err != nil {
      c.JSON(200, gin.H{"msg": "你错了"})
      return
    }
    c.JSON(200, userInfo)

  })
  router.Run(":80")
}

ShouldBindQuery

绑定查询参数

tag对应为form

// ?name=枫枫&age=21&sex=男
package main

import (
  "fmt"
  "github.com/gin-gonic/gin"
)

type UserInfo struct {
  Name string `json:"name" form:"name"`
  Age  int    `json:"age" form:"age"`
  Sex  string `json:"sex" form:"sex"`
}

func main() {
  router := gin.Default()

  router.POST("/query", func(c *gin.Context) {

    var userInfo UserInfo
    err := c.ShouldBindQuery(&userInfo)
    if err != nil {
      fmt.Println(err)
      c.JSON(200, gin.H{"msg": "你错了"})
      return
    }
    c.JSON(200, userInfo)

  })
  router.Run(":80")
}

ShouldBindUri

绑定动态参数

tag对应为uri

// /uri/fengfeng/21/男

package main

import (
  "fmt"
  "github.com/gin-gonic/gin"
)

type UserInfo struct {
  Name string `json:"name" form:"name" uri:"name"`
  Age  int    `json:"age" form:"age" uri:"age"`
  Sex  string `json:"sex" form:"sex" uri:"sex"`
}

func main() {
  router := gin.Default()

  router.POST("/uri/:name/:age/:sex", func(c *gin.Context) {

    var userInfo UserInfo
    err := c.ShouldBindUri(&userInfo)
    if err != nil {
      fmt.Println(err)
      c.JSON(200, gin.H{"msg": "你错了"})
      return
    }
    c.JSON(200, userInfo)

  })

  router.Run(":80")
}


ShouldBind

会根据请求头中的content-type去自动绑定

form-data的参数也用这个,tag用form

默认的tag就是form

绑定form-data、x-www-form-urlencode

package main

import (
  "fmt"
  "github.com/gin-gonic/gin"
)

type UserInfo struct {
  Name string `form:"name"`
  Age  int    `form:"age"`
  Sex  string `form:"sex"`
}

func main() {
  router := gin.Default()
  
  router.POST("/form", func(c *gin.Context) {
    var userInfo UserInfo
    err := c.ShouldBind(&userInfo)
    if err != nil {
      fmt.Println(err)
      c.JSON(200, gin.H{"msg": "你错了"})
      return
    }
    c.JSON(200, userInfo)
  })

  router.Run(":80")
}