探索Gin框架:Golang Gin框架请求参数的获取

简介: 探索Gin框架:Golang Gin框架请求参数的获取

前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站https://www.captainbed.cn/kitie


前言

我们在专栏的前面几篇文章内讲解了Gin框架的路由配置,服务启动等内容。


在我们平常添加路由处理函数之后,就可以在路由处理函数中编写业务处理代码了,但在此之前我们往往需要获取请求参数,本文就详细的讲解下gin获取请求参数常见的几种方式。


传递参数的方式

在一个HTTP请求中,一般可以把上传参数分为以下三个部分:

Header是HTTP请求中一个键值对集合,HTTP规范定义了很多的Headeer,比如Content-Type,Accept等,不过也可以自定义请求头部或者响应头部。


URL

URL指的是请求路径,在请求路径上可以通过两种方式携带请求参数,一种是直接写在请求路径上的,称为URL Path:

http://localhost:8080/user/add


在URL上传递参数的另外一种方式就是URL Query,URL Query参数是指跟在?后面的键值对集合,多个参数之间以&分隔的:

http://localhost:8080/user/add?name=小明&gender=男


HTTP Body

HTTP Body参数是指HTTP请求的请求体所携带的参数,这部分参数会因为Content-Type不同而不同,比如当Content-Type为application/json时,HTTO Body携带的是一串JSON字符串。


那么,在Gin框架中,要如何获取这些请求参数呢?主要有以下两种方式:


直接用Gin封装的方法获取请求参数

通过绑定的方式来获取请求参数

直接获取请求参数

Gin框架在net/http包的基础上封装了获取参数的方式。

获取URL Path中的参数

在路由中使用通配符时,对应的通配符就会成为URL Path参数,调用gin.Context的Param()方法可以获取Path参数:

 package main
 func main(){
   engine := gin.Default()
   engine.GET("/user/:id", func(ctx *gin.Context) {
     id := ctx.Param("id")
     fmt.Fprintf(ctx.Writer, "你的请求id:%s", id)
   })
     engine.Run()
 }

运行后发起请求:

 $ curl http://localhost:8080/user/100
 你的请求id:100


获取URL Query中的参数

gin.Context对象提供了以下几个主要方法用于获取Query参数:

 package main
 import (
   "fmt"
   "github.com/gin-gonic/gin"
 )
 func main() {
   engine := gin.New()
   engine.GET("/user/list", func(ctx *gin.Context) {
     //获取单个值
     name := ctx.Query("name")
     //带默认值
     gender := ctx.DefaultQuery("gender", "男")
     //数组
     habits := ctx.QueryArray("habits")
     //map
     works := ctx.QueryMap("works")
     fmt.Printf("%s,%s,%s,%s\n", name, gender, habits, works)
   })
   engine.Run()
 }

运行后发起请求:

curl -X GET "http://localhost:8080/user/list?name=John&gender=男&habits[]=reading&habits[]=sports&works[teacher]=math&works[engineer]=computer"
John,男,[reading sports],map[engineer:computer teacher:math]

获取HTTP Body中的参数

对于通过HTTP Body传上来的参数,gin.Context也提供了几种主要方法用于获取:

 package main
 import (
   "fmt"
   "github.com/gin-gonic/gin"
 )
 func main() {
   engine := gin.New()
   engine.POST("/user/add", func(ctx *gin.Context) {
     //获取单个值
     name := ctx.PostForm("name")
     //带默认值
     gender := ctx.DefaultPostForm("gender", "男")
     //数组
     habits := ctx.PostFormArray("habits")
     //map
     works := ctx.PostFormMap("works")
     fmt.Printf("%s,%s,%s,%s\n", name, gender, habits, works)
   })
   engine.Run()
 }


绑定请求参数

Gin支持绑定Header,URL Path,URL Query以及HTTP Body等不同位置数据。

绑定Header参数

绑定Header参数可以使用BindHeader()或者ShouldBindHeader()方法:

 package main
 import (
   "fmt"
   "net/http"
   "github.com/gin-gonic/gin"
 )
 type testHeader struct {
   Rate   int    `header:"Rate"`
   Domain string `header:"Domain"`
 }
 func main() {
   r := gin.Default()
   r.GET("/", func(c *gin.Context) {
     h := testHeader{}
     if err := c.ShouldBindHeader(&h); err != nil {
       c.JSON(http.StatusBadRequest, err)
       return
     }
     fmt.Printf("%#v\n", h)
     c.JSON(http.StatusOK, gin.H{"Rate": h.Rate, "Domain": h.Domain})
   })
   r.Run()
 }

运行后的请求结果:

$ curl -H "rate:300" -H "test:123" http://localhost:8080/
{"Test":"123","Rate":300}

绑定URL Path参数

绑定URL Path参数可以使用BindUri()或者ShouldBindUri()方法:

package main
 
import (
  "fmt"
  "net/http"
 
  "github.com/gin-gonic/gin"
)
 
type User struct {
  Name  string `uri:"name"`
  Email string `uri:"email"`
}
 
func main() {
  engine := gin.New()
  engine.GET("/user/list/:email/:name", func(ctx *gin.Context) {
    var u User
    if err := ctx.BindUri(&u);err != nil {
      ctx.JSON(http.StatusBadRequest, err)
      return
    }
    fmt.Fprintf(ctx.Writer, "你输入的用户名为:%s,邮箱为:%s\n", u.Name, u.Email)
  })
  engine.Run()
}

运行后的请求结果:

curl -X GET "http://localhost:8080/user/list/john@163.com/john
你输入的用户名为:john,邮箱为:john@163.com

绑定URL Query参数

绑定URL Query参数可以使用BindQuery()、ShouldBindQury()、Bind()或者ShouldBind()方法:

package main
 
import (
  "fmt"
  "net/http"
 
  "github.com/gin-gonic/gin"
)
 
type User struct {
  Name  string `form:"name"`
  Email string `form:"email"`
}
 
func main() {
  engine := gin.New()
  engine.GET("/user/list", func(ctx *gin.Context) {
    var u User
    if err := ctx.BindQuery(&u);err != nil {
      ctx.JSON(http.StatusBadRequest, err)
      return
    }
    fmt.Fprintf(ctx.Writer, "你输入的用户名为:%s,邮箱为:%s\n", u.Name, u.Email)
  })
 
  engine.Run()
}

运行后的请求结果:

curl -X GET "http://localhost:8080/user/list?email=john@163.com&name=john
你输入的用户名为:john,邮箱为:john@163.com

绑定HTTP Body参数

我们知道HTTP Body的参数会根据不同Content-Type传不同格式的数据,Gin支持以下几种Content-Type类型的绑定:

  • JSON
  • XML
  • TOML
  • YAML
  • x-www-form-urlencoded
  • multipart/form-data

注意HTTP Body的数据只在POST请求时才会进行绑定。


绑定HTTP Body参数可以用Bind()和ShouldBind()方法,这两个方法会根据当前请求的Content-Type类型自动判断请求的类型。

package main
 
import (
  "fmt"
  "net/http"
 
  "github.com/gin-gonic/gin"
)
 
type User struct {
  Name  string
  Email string
}
 
func main() {
  engine := gin.New()
  engine.POST("/user/add", func(ctx *gin.Context) {
    var u User
    if err := ctx.Bind(&u); err != nil {
      ctx.JSON(http.StatusBadRequest, err.Error())
      return
    }
    fmt.Fprintf(ctx.Writer, "你输入的用户名为:%s,邮箱为:%s\n", u.Name, u.Email)
  })
  engine.Run()
}


如果明确请求数据的类型,也可以直接调用对应类型绑定的方法,比如确定是JSON格式数据的话,可以调用BindJSON()或者ShouldBindJSON():

package main
 
import (
  "fmt"
  "net/http"
 
  "github.com/gin-gonic/gin"
)
 
type User struct {
  Name  string
  Email string
}
 
func main() {
  engine := gin.New()
  engine.POST("/user/add", func(ctx *gin.Context) {
    var u User
    if err := ctx.BindJSON(&u); err != nil {
      ctx.JSON(http.StatusBadRequest, err.Error())
      return
    }
    fmt.Fprintf(ctx.Writer, "你输入的用户名为:%s,邮箱为:%s\n", u.Name, u.Email)
  })
  engine.Run()
}


对于x-www-form-urlencoded和multipart/form-data,与Qurey参数一样,结构体需要添加form的tag:

package main
 
import (
  "fmt"
  "net/http"
 
  "github.com/gin-gonic/gin"
)
 
type User struct {
  Name  string `form:"name"`
  Email string `form:"email"`
}
 
func main() {
  engine := gin.New()
  engine.POST("/user/add", func(ctx *gin.Context) {
    var u User
    if err := ctx.Bind(&u); err != nil {
      ctx.JSON(http.StatusBadRequest, err.Error())
      return
    }
    fmt.Fprintf(ctx.Writer, "你输入的用户名为:%s,邮箱为:%s\n", u.Name, u.Email)
  })
  engine.Run()
}


数据校验

在数据绑定的时候,也可以进行数据校验,这里我们为User结构体的标签添加了required属性,要求这个字段必须要有:

package main
 
import (
  "fmt"
  "net/http"
 
  "github.com/gin-gonic/gin"
)
 
type User struct {
  Name  string `binding:"required"`
  Email string `binding:"required"`
}
 
func main() {
  engine := gin.New()
  engine.POST("/user/add", func(ctx *gin.Context) {
    var u User
    if err := ctx.Bind(&u); err != nil {
      ctx.JSON(http.StatusBadRequest, err.Error())
      return
    }
    fmt.Fprintf(ctx.Writer, "你输入的用户名为:%s,邮箱为:%s\n", u.Name, u.Email)
  })
  engine.Run()
}



两种方式的对比


相较于直接获取请求参数,请求数据绑定是一种更强大且优雅的参数获取方式,使用这种方式获取参数有以下几个好处:


直接将所有参数绑定到一个结构体中,不需要手动一个个地获取参数。

绑定后的参数会自动转换为结构体对应字段的类型,不需要手动对每个参数进行数据类型转换。

在进行数据绑定的同时还可以进行数据校验。

小结

直接获取请求参数虽然没有绑定参数那么强大,但对于简单的请求来说,也是够用的,因此,我们可以根据自己的需求,选择对应的方式来获取请求参数。

相关文章
|
9天前
|
SQL 关系型数据库 MySQL
探索Gorm - Golang流行的数据库ORM框架
探索Gorm - Golang流行的数据库ORM框架
|
9天前
|
存储 人工智能 Go
探索Gin框架:Golang使用Gin完成文件上传
探索Gin框架:Golang使用Gin完成文件上传
|
9天前
|
存储 中间件 Go
探索Gin框架:快速构建高性能的Golang Web应用
探索Gin框架:快速构建高性能的Golang Web应用
|
11天前
|
存储 测试技术 Go
Golang框架实战-KisFlow流式计算框架(2)-项目构建/基础模块-(上)
KisFlow项目源码位于<https://github.com/aceld/kis-flow,初始阶段涉及项目构建和基础模块定义。首先在GitHub创建仓库,克隆到本地。项目目录包括`common/`, `example/`, `function/`, `conn/`, `config/`, `flow/`, 和 `kis/`。`go.mod`用于包管理,`KisLogger`接口定义了日志功能,提供不同级别的日志方法。默认日志对象`kisDefaultLogger`打印到标准输出。
420 1
Golang框架实战-KisFlow流式计算框架(2)-项目构建/基础模块-(上)
|
1天前
|
前端开发 Go
Golang深入浅出之-Go语言中的异步编程与Future/Promise模式
【5月更文挑战第3天】Go语言通过goroutines和channels实现异步编程,虽无内置Future/Promise,但可借助其特性模拟。本文探讨了如何使用channel实现Future模式,提供了异步获取URL内容长度的示例,并警示了Channel泄漏、错误处理和并发控制等常见问题。为避免这些问题,建议显式关闭channel、使用context.Context、并发控制机制及有效传播错误。理解并应用这些技巧能提升Go语言异步编程的效率和健壮性。
11 5
Golang深入浅出之-Go语言中的异步编程与Future/Promise模式
|
1天前
|
监控 负载均衡 算法
Golang深入浅出之-Go语言中的协程池设计与实现
【5月更文挑战第3天】本文探讨了Go语言中的协程池设计,用于管理goroutine并优化并发性能。协程池通过限制同时运行的goroutine数量防止资源耗尽,包括任务队列和工作协程两部分。基本实现思路涉及使用channel作为任务队列,固定数量的工作协程处理任务。文章还列举了一个简单的协程池实现示例,并讨论了常见问题如任务队列溢出、协程泄露和任务调度不均,提出了解决方案。通过合理设置缓冲区大小、确保资源释放、优化任务调度以及监控与调试,可以避免这些问题,提升系统性能和稳定性。
12 6
|
1天前
|
安全 Go
Golang深入浅出之-Go语言中的并发安全队列:实现与应用
【5月更文挑战第3天】本文探讨了Go语言中的并发安全队列,它是构建高性能并发系统的基础。文章介绍了两种实现方法:1) 使用`sync.Mutex`保护的简单队列,通过加锁解锁确保数据一致性;2) 使用通道(Channel)实现无锁队列,天生并发安全。同时,文中列举了并发编程中常见的死锁、数据竞争和通道阻塞问题,并给出了避免这些问题的策略,如明确锁边界、使用带缓冲通道、优雅处理关闭以及利用Go标准库。
12 5
|
2天前
|
存储 缓存 安全
Golang深入浅出之-Go语言中的并发安全容器:sync.Map与sync.Pool
Go语言中的`sync.Map`和`sync.Pool`是并发安全的容器。`sync.Map`提供并发安全的键值对存储,适合快速读取和少写入的情况。注意不要直接遍历Map,应使用`Range`方法。`sync.Pool`是对象池,用于缓存可重用对象,减少内存分配。使用时需注意对象生命周期管理和容量控制。在多goroutine环境下,这两个容器能提高性能和稳定性,但需根据场景谨慎使用,避免不当操作导致的问题。
17 4
|
2天前
|
安全 Go 开发者
Golang深入浅出之-Go语言中的CSP模型:深入理解并发哲学
【5月更文挑战第2天】Go语言的并发编程基于CSP模型,强调通过通信共享内存。核心概念是goroutines(轻量级线程)和channels(用于goroutines间安全数据传输)。常见问题包括数据竞争、死锁和goroutine管理。避免策略包括使用同步原语、复用channel和控制并发。示例展示了如何使用channel和`sync.WaitGroup`避免死锁。理解并发原则和正确应用CSP模型是编写高效安全并发程序的关键。
21 4
|
3天前
|
安全 Go 开发者
Golang深入浅出之-Go语言中的CSP模型:深入理解并发哲学
【5月更文挑战第1天】Go语言基于CSP理论,借助goroutines和channels实现独特的并发模型。Goroutine是轻量级线程,通过`go`关键字启动,而channels提供安全的通信机制。文章讨论了数据竞争、死锁和goroutine泄漏等问题及其避免方法,并提供了一个生产者消费者模型的代码示例。理解CSP和妥善处理并发问题对于编写高效、可靠的Go程序至关重要。
13 2