go语言web框架之gin用法
Gin是一个用Go语言编写的web框架,由于使用了httprouter,速度提高了近40倍,通过go doc gin可查看具体哟用法
1、下载并安装Gin,命令如下:
go get -u github.com/gin-gonic/gin
2、下面是一个简单的gin例子,如图:

- 第10行:初始化一个gin引擎,除了Default外还可以通过gin.New(),二者区别:gin.Default()里面调用了gin.New();在调用完gin.New()得到Engine 实例后,还调用了engine.Use(Logger(), Recovery());gin.Default()获取到的Engine 实例集成了Logger 和 Recovery 中间件
- 第11行:定义路由,方法为GET,第一个参数为路由的路径,第二个参数为函数,详解见下方
- 第14行:JSON为gin.Context中的方法,用于返回JSON数据格式,语法为: func (c *Context) JSON(code int, obj any),第一个参数表示返回代码,后面的any表示接收任意参数,any就是一个空接口,在any.go中定义的,gin.H为一个map类型,调用c.JSON主要返回第二各参数any
- 第20行:启动引擎执行监控,如果不设置端口,默认端口为8080
启动go文件,如图:

通过Postman请求结果如下:

详细实现说明:
(1)、首先查看gin.Default()的返回类型(gin.New()一样),可以看到返回为*Engine,如图:

(2)、查看结构体Engine,可以看到其中嵌套了路由组RouterGroup结构体,如图:

(3)、查看路由组RouterGroup结构体的方法如下:

从上图看出,路由组中包含了我们访问的GET、POST等方法,因此实际请求的时候router.GET实际就是请求的路由组RouterGroup中的方法,方法包含两个参数,第一个参数为字符串,表示路径,第二个参数HandlerFunc其实是一个不定参数的函数(可以接受任意数量的参数)
(4)、查看参数HandlerFunc的类型,如图:

从上图看出,HandlerFunc类型其实是参数为gin.Context的函数,因此在此函数中就可以执行gin.Context中的各类方法了,比如JSON、Bind、ShouldBind等,具体用法通过go doc gin Context查询
3、gin中的FormFile方法用于获取上传文件的信息,参考链接如下:
https://blog.ywdevops.cn/index.php/2022/12/16/upload/
4、gin中的ShouldBindJSON用来绑定传递的json数据,如图:

通过postman请求,如图:

注:在使用ShouldBindJSON时,结构体标签form可写可不写,在使用postman请求的时候,password字段后不能有逗号,否则不符合json格式,会报错的
5、通过Bind()方法绑定数据
下面例子表示通过Bind()方法将数据绑定到结构体test上,Username为必选字段,Password为可选,ctx.JSON中的第一个参数设置为http.StatusForbidden,表示状态码为403,如图:

通过postman调用的时候,将password类型输入为字符串,如图:

可看到postman返回的状态码为400,也就是说如果Bind()绑定失败会在返回400状态码
6、通过ShouldBind()方法绑定数据
修改上图中的方法,将Bind()改为ShouldBind(),如图:

再次执行postman,可以看到状态码为我们自定义的403,如图:

7、Param()方法用于从HTTP请求的URL路径中获取参数值,语法如下:
func (c *Context) Param(key string) string
下面例子表示通过动态路由来下载机器上的文件,如下:
package main
import (
"fmt"
"net/http"
"os"
"github.com/gin-gonic/gin"
)
func main() {
router := gin.New()
//定义动态路由
router.GET("/getFile/:filename", func(c *gin.Context) {
f := c.Param("filename") //获取参数值
filePath := "/tmp/" + f
_, err := os.Stat(filePath)
if os.IsNotExist(err) { //判断文件是否存在
c.String(http.StatusNotFound, "file not found")
return
}
c.Header("Content-Disposition", fmt.Sprintf("attachment; filename=%s", f))
c.Header("Content-Description", "File Transfer")
c.Header("Content-Type", "application/octet-stream")
c.File(filePath) //将文件发送给客户端
})
router.Run()
}
通过浏览器访问http://ip/getFile/a.txt即可实现下载a.txt文件
8、通过QueryArray()来获取参数并返回字符串切片,语法如下:
func (c *Context) QueryArray(key string) (values []string)
下面例子通过GET方法,传递参数并通过QueryArray来获取参数,如图:


9、通过PostForm()获取POST请求中从body中传递过来的数据,语法如下:
func (c *Context) PostForm(key string) (value string)
下面例子定义POST请求,通过Body方式传递参数,如图:

通过postman请求,如图:

注意:通过Body方式来传递参数要选择x-www-form-urlencoded,x-www-form-urlencoded适用于传输简单的键值对数据,还有一种是通过url传递参数,此时就要选择Params了
10、通过BindJSON()绑定POST请求中传递的JSON数据
下面例子中发送POST请求,传递JSON数据,并绑定到结构体中,如图:

通过postman请求,选择raw,然后定义JSON数据,如图:

raw是一种直接发送原始数据的方式,可以是纯文本、JSON、XML 等格式。数据以原始的形式发送,没有特定的编码格式
注:BindJSON()和ShouldBindJSON()都用来绑定JSON数据,但是BindJSON()会将错误放在header中,而ShouldBindJSON()则直接返回错误
11、通过ShouldBindWith()来绑定数据
ShouldBindWith()方法是ShouldBind、ShouldBindJSON、ShouldBindXML等这些绑定方法的底层方法,如图:

查看ShouldBindWith()方法的语法如下:

ShouldBindWith的第二个参数是Binding接口,这意味着实现了这个接口方法的结构体都可以作为参数传入
查看Binding接口,位于gin库下的binding包里面,如下:

Binding接口的Bind方法,就是实现参数绑定的核心,目前有十二种绑定引擎可用,如下:

上图中的12个结构体都实现了接口Binding ,因此可直接作为参数传递给Binding,例如上图中的ShouldBindJSON()方法,直接调用的ShouldBindWith的时候直接指定的binding.JSON,因此直接调用jsonBinding结构体中的Bind()方法进行绑定,其余的都是一样,但是ShouldBind()除外,因此这个方法中还有一个Default()函数(如上图),在binding.go中定义,查看Default()函数的语法如下:

从上图看出,如果请求的方法为GET,那么直接返回Form,也就是表单绑定,如果不是GET,也就是POST,此时就要判断contentType了,根据客户端传递的contentType不同,返回不同类型,MIMEJSON表示常量,已经在binding.go中定义,如图:

从上图的switch-case中看到,如果没有指定任何常量,那么默认情况下返回Form,也就是表单绑定,因此ShouldBind()默认情况下实现的就是表单绑定
下面是一个使用ShouldBindWith()的例子,主要功能是通过POST发送请求的时候,传递参数同时还上传图片,如下:
package main
import (
"log"
"net/http"
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/binding"
)
type username struct {
Username string `form:"username" valid:"Required"`
}
func main() {
router := gin.New()
router.POST("/upload", func(c *gin.Context) {
var form username
err := c.ShouldBindWith(&form, binding.Form)
if err != nil {
log.Fatal(err)
}
m, e := c.FormFile("image")
if e != nil {
log.Fatal(e)
}
c.JSON(http.StatusOK, gin.H{
"code": 1000,
"msg": "ok",
"data": form.Username,
"filename": m.Filename,
})
})
router.Run()
}
- ShoueldBindWith中指定了binding.Form


上面例子为什么不用ShouldBind而是直接使用ShouldBindWith呢?
因为在 Gin 框架中,一旦使用了 FormFile 方法获取上传的文件,Gin 会自动将请求的 Content-Type 设置为 multipart/form-data,这会导致 ShouldBind 方法无法正确解析请求的参数,为了解决这个问题,可以使用 ShouldBindWith 方法并指定 form 绑定标签来手动解析参数。这样可以绕过 ShouldBind 方法对 Content-Type 的检查
注:Content-Type 字段是用来告诉服务端接收到的数据的类型,它是由客户端在发送请求时设置的。虽然该字段在请求头中,但它是为了服务端而存在的,用于指示服务端如何解析请求体中的数据,客户端在发送请求时通过设置 Content-Type 字段来告知服务端请求体中包含的数据的类型。服务端根据该字段的值来解析请求体中的数据,并做出相应的处理。例如,如果 Content-Type 是 application/json,服务端就会将请求体中的数据解析为 JSON 格式,服务端根据 Content-Type 字段来确定如何处理请求体中的数据,以确保正确解析和处理请求。因此,Content-Type 字段是给服务端看的,用于指示服务端如何处理请求体中的数据类型。客户端设置正确的 Content-Type 字段可以帮助服务端正确地处理请求,并提供正确的响应


