go语言 gin框架学习系列(二):Gin框架 接收请求参数 和 响应请求参数 的各种方式

292 阅读3分钟

1.接收请求参数

c.Param()  
c.Query  
c.DefaultQuery  
c.PostForm  
c.DefaultPostForm  
c.QueryMap  
c.PostFormMap  
c.FormFile  
c.MultipartForm

1.1 GET请求参数(c.Query)

func main() {
    r := gin.Default()
    r.GET("/user", func(c *gin.Context) {
       // 使用query获取请求参数         
       username := c.Query("username")
       password := c.Query("password")
       
       fmt.Println(username) // linjing
       fmt.Println(password) // 123
       
       // 返回请求参数 JSON
       c.JSON(200, gin.H{
          "username": username,
          "password": password,
       })
    })

    // 运行服务
    r.Run(":8080")
}

postman 测试: 127.0.0.1:8080/user?username=linjing&password=123

image.png

1.2 POST请求参数-Form表单(c.PostForm)

func main() {
    r := gin.Default()
    // 使用POST请求并获取参数
    r.POST("/user", func(c *gin.Context) {
       // 使用PostForm获取请求参数
       username := c.PostForm("username")
       password := c.PostForm("password")

       // 返回请求参数 JSON
       c.JSON(200, gin.H{
          "username": username,
          "password": password,
       })
    })

    // 运行服务
    r.Run(":8080")
}

image.png

1.3 POST请求参数-JSON格式(c.BindJSON)

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

    // 使用POST请求并获取参数
    r.POST("/user", func(c *gin.Context) {
       var user User
       if err := c.BindJSON(&user); err != nil {
          // 返回错误信息
          c.JSON(http.StatusBadRequest, gin.H{
             "error": err.Error(),
          })
          return
       }

       // 返回请求参数
       c.JSON(200, gin.H{
          "username": user.Username,
          "password": user.Password,
       })
    })

    r.Run(":8080")
}

type User struct {
    Username string `json:"username"`
    Password string `json:"password"`
}

image.png

1.4 URL参数

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

    // 使用url传参  并获取参数
    r.GET("/user/:username/:password", func(c *gin.Context) {
       // 使用param获取URL参数
       username := c.Param("username")
       password := c.Param("password")

       // 返回请求参数
       c.JSON(200, gin.H{
          "username": username,
          "password": password,
       })
    })

    // 运行服务
    r.Run(":8080")
}

image.png

1.5 请求头部参数

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

    // 使用请求头参数
    r.GET("/user", func(c *gin.Context) {
       // 使用request获取请求头参数
       username := c.Request.Header.Get("username")
       password := c.Request.Header.Get("password")

       // 返回请求参数
       c.JSON(200, gin.H{
          "username": username,
          "password": password,
       })

    })
    // 运行服务
    r.Run(":8080")
}

image.png

2. 响应请求参数

1.BindJSON()

通过BindJSON()将json请求体绑定到一个结构体上。

type User struct {
    Username string `json:"username"`
    Password string `json:"password"`
}

// main()中代码
var user User
if err := c.BindJSON(&user); err != nil {
    // 返回错误信息
    c.JSON(http.StatusBadRequest, gin.H{
       "error": err.Error(),
    })
    return
}
fmt.Println(user.Username)
fmt.Println( user.Password)

2.gin的BindJSON() ShouldBindJSON() 区别

BindJSON():返回错误,并在header里面写400状态码。(多返回了http.StatusBadRequest)

// BindJSON is a shortcut for c.MustBindWith(obj, binding.JSON).
func (c *Context) BindJSON(obj any) error {
    return c.MustBindWith(obj, binding.JSON)
}

func (c *Context) MustBindWith(obj any, b binding.Binding) error {
    if err := c.ShouldBindWith(obj, b); err != nil {
       c.AbortWithError(http.StatusBadRequest, err).SetType(ErrorTypeBind) //nolint: errcheck
       return err
    }
    return nil
}

ShouldBindJSON():只会返回错误信息,不会往header中写400的错误状态码。(没有状态码,多了个默认参数b为JSON)

// ShouldBindJSON is a shortcut for c.ShouldBindWith(obj, binding.JSON).
func (c *Context) ShouldBindJSON(obj any) error {
    return c.ShouldBindWith(obj, binding.JSON)
}

func (c *Context) ShouldBindWith(obj any, b binding.Binding) error {
    return b.Bind(c.Request, obj)
}

3.其他

疑问: 类似的方法c.ShouldBind(),c.Bind,c.ShouldBind()等,有什么区别?

响应数据绑定方法:

c.Bind
c.BindJSON
c.BindXML
c.BindQuery
c.BindYAML
c.ShouldBind
c.ShouldBindJSON
c.ShouldBindXML
c.ShouldBindQuery
c.ShouldBindYAML

以上方法区别总结:

带should和不带should的,最大区别就是响应带不带状态码。

bind后不同的类型,比如JSON,XML.Query等,区别是b参数默认相应类型。

bind后不加任何,shouBind()方法可以根据请求中contentType的不同类型,采用不同的方式进行处理(无论是QueryString/PostForm/JSON数据)。

    //内部根据Content-Type去解析
    c.ShouldBind(obj interface{})
    //内部替你传递了一个binding.JSON,对象去解析
    c.ShouldBindJSON(obj interface{})
    //解析哪一种绑定的类型,根据你的选择
    c.ShouldBindWith(obj interface{}, b binding.Binding)

参考链接:juejin.cn/post/714249…

四种常见的POST数据提交方式:content-type值

application/x-www-form-urlencoded enctype不设置    浏览器原生form表单
enctype 设置为 multipart/form-data  表单上传文件
application/json  序列化后的 JSON 字符串
text/xml  提交xml文件
参考链接:https://imququ.com/post/four-ways-to-post-data-in-http.html

其实,还有之前接触的一种简单的响应,差点忽略,就是不绑定结构体,响应数据直接为c.String()的。

c.String()
c.JSON()
c.HTML()
c.XML()
c.YAML()

实例:


c.String(200, "%v", "Hello World")

c.JSON(200,gin.H{
	"success":true,
	"msg":"你好 gin",
})


r.LoadHTMLGlob("templates/*")
c.HTML(200, "index.html", gin.H{
	"time":     "20xx年x月x日",
	"location": "xx市",
	"weather":  "晴",
})

/templates/index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    {{.time}}<br>
    {{.location}}<br>
    {{.weather}}
</body>
</html>

总结小点

1.gin.H

gin.H 实际上就是 map[string]interface{}的缩写 源码中为:

// H is a shortcut for map[string]any
type H map[string]any
c.JSON(http.StatusOK, map[string]interface{}{ "status": "登录成功"}) // 标准库写法
// 等价于
c.JSON(http.StatusOK, gin.H{ "status": "登录成功"}) // gin

参考链接:juejin.cn/post/721317…

3.接收请求->查数据库的大致过程

image.png

router: 路由对应处理函数。

r.POST("create", controlor.Create)

controlor:处理函数层 主要校验参数,构造响应数据

func Create(c *gin.Context) {

newId, err := service.Create(&input, c)
    data := response.User{  
        Id: newId,  
    }  
  response.SuccessWithData(data, c)
}

service:服务层,主要调用多个model中的方法,查找多张数据表,组合返回数据。

func (u *User) Create(user *model.User, c *gin.Context) (newId uint, err error) {
    newId = model.CreateUser()
    return 
}

model:数据层,查找对应表的各种方法。

type User struct {  
  NewId  int   `json:new_id`
}

func  CreateUser() error {  
    // 查数据库
    query := db.Model(&User{})  
    query = query.Select(查找条件)  
    
    return 结果  
}