大家好,我是渔夫子。
在gin框架中,咱们晓得用bind函数(或bindXXX函数)可能将申请体中的参数绑定到对应的构造体上。同时,你也会发现在gin中有很多bind或bindXXX函数,比方ShouldBind、ShouldBindQuery、ShouldBindHeader、ShouldBindJSON等等。那么,他们之间有什么不同呢?本文带你深刻理解这些bind函数的应用。
一、bind的根本作用
在gin框架或其余所有web框架中,bind或bindXXX函数(后文中咱们对立都叫bind函数)的作用就是将申请体中的参数值绑定到对应的构造体上,以不便后续业务逻辑的解决。
接下来咱们看一个简略的应用例子,该实例是冀望客户端发送一个JSON格局的申请体,而后通过JSON标签绑定到LoginRequest构造体上。如下:
package main
import (
"fmt"
"github.com/gin-gonic/gin"
)
type LoginRequest struct {
Username string `json:"username"`
Password string `json:"password"`
}
func main() {
g := gin.New()
g.POST("/login", func(ctx *gin.Context) {
r := &LoginRequest{}
ctx.ShouldBind(r)
fmt.Printf("login-request:%+v\n", r)
})
g.Run(":9090")
}
运行上述示例代码,并在postman中或应用curl给http://localhost:9090/login发送申请,申请体是:
curl -X POST -H "Content-Type:application/json" http://localhost:9090/login -d '{"username": "yufuzi", "password": "123456}'
在代码中,咱们通过ctx.ShouldBind(r)函数,将申请体的内容绑定到了LoginRequest类型的r变量上。
咱们通过ShouldBind函数的源代码能够梳理到绑定函数的个别流程:
1、调用ctx.ShouldBind函数
2、ShouldBind函数依据申请的办法(POST还是GET)以及Content-Type获取具体的bind实例。如是POST申请且申请体是JSON格局,那么就返回jsonBinding构造体实例。
3、调用ctx.ShouldBindWith函数
4、ShouldBindWith函数调用具体的绑定实例的Bind办法。例如jsonBinding.Bind函数
5、将request中的Body(或Form、Header、Query)中的申请值绑定到对应的构造体上。
其大抵流程如下:
二、申请数据起源
由第一节咱们理解到,数据来源于客户端发来的申请。那么,在一次http申请中,都能够通过哪里来携带参数呢?依据http协定的规范,能够通过url中的查问参数,申请头、申请体等路径将参数传递给服务端。
在申请体中参数能够是不同的格局,比方JSON格局、XML格局、YAML格局、TOML格局、Protobuf message等。也能够是form表单的模式。
有了起源,接下来看看各个bind函数是如何把不同数据源的数据绑定到构造体上的。
三、bind及其bindXXX函数
为了可能不便解析不同起源的申请数据及不同格局的数据,在gin框架中就对应了不同的bind及bindXXX函数来解析对应的申请数据。以下就是对应的数据起源及不同格局的函数。
ShouldBindQuery函数
首先是来源于url地址中的查问参数,对应的解析函数是ShouldBindQuery
,构造体中通过给字段减少query
标签即可关联。如下:
ShouldBindHeader函数
其次是来源于申请头中的参数,对应的解析函数是ShouldBindHeader,构造体中通过给字段减少header
标签即可关联。如下:
ShouldBindXXX函数
而后是来源于申请体中的参数,这个稍微简单。若申请体是一般的文本格式的话,能够是JSON、XML、TOML、YAML或者protobuf、msgpack格局。能够对应ShouldBindXXX函数,如下:
若申请体是以表单模式发送数据的,会有formBinding、formPostBinding以及formMultipartBinding三个构造体。那这三个binding有什么区别呢?要想搞清楚三个构造体之间的区别,就要从form的enctype属性说起。
form的enctype属性
在html中,咱们发送表单时个别会用<form>标签,但form标签有一个enctype
属性,该属性个别有两个值:multipart/form-data和application/x-www-form-urlencoded。这两个值什么意思呢?
属性为application/x-www-form-urlencoded
enctype为该属性时,代表将form中的值在发送给服务端时,会将form中的值组织成key1=value1&key2=value2这样的类型发送。如下:
<form action="http://localhost:9090/login?utm_source=login" method="POST" enctype="application/x-www-form-urlencoded">
<input type="text" name="username" value="yufuzi" />
<input type="text" name="password" />
<input type="file" name="f" />
<input type="submit" value="submit" />
</form>
当咱们提交订单时,浏览器发送给服务端的申请参数会被编码成如下模式:
属性值为multipart/form-data
该属性值代表表白是能够发送二进制的数据,比方文件。如下:
<form action="http://localhost:9090/login?utm_source=login" method="POST" enctype="multipart/form-data">
<input type="text" name="username" value="yufuzi" />
<input type="text" name="password" />
<input type="file" name="f" />
<input type="submit" value="submit" />
</form>
同时,咱们还发现在post的表单中,action的地址还能够带查问参数,即?utm_source=login参数。所以一个表单中可能携带参数的中央有:
- url地址中的查问参数。
- 表单的值域。即input控件。
依据发送时的编码方式又能够将值域参数分为按url查问参数编码的形式和混合形式。
gin申请中的Form、PostForm、MultipartForm构造体
依据申请参数起源的不同,在gin中也有对应的Form对象来承载对应的值。在go的net/http包的Request构造体中,咱们发现有Form、PostForm、MultipartForm对象。这些对象就是别离承载不同起源的申请参数的。
- Form对象:其值来源于url地址中的查问参数和表单中的值域两局部。以上述login的表单为例,Form中的值则是utm_source=login, username=yufuzi,password=123456
- PostForm对象:其值来源于表单中的值域。以上述login的表单为例,PostForm中的值则是username=yufuzi,password=123456
- MultipartForm对象:其值来源于表单中的文件的值。以上述login的表单为例,MultipartForm中的值分为两局部,一部分是Values值,保留的是username=yufuzi,password=123456的值。一部分是文件的值,保留的是f中的文件句柄。
当然,在绑定申请参数的时候也有对应的bind办法。
在gin中对应的办法为ctx.ShouldBindWith(obj, binding.Form)
。当然,在应用ctx.ShouldBind办法时,默认也是绑定request.Form中的数据到构造体。
通过ctx.ShouldBindWith(obj, binding.FormPost)函数,能够将request.PostForm中的申请参数值绑定到对应的构造体上,如下:
通过ctx.ShouldBindWith(obj, binding.MIMEMultipartPOSTForm)函数,能够将request.PostForm中的申请参数值绑定到对应的构造体上,如下:
gin中bind函数的残缺层级构造
在gin中,要将申请体绑定到构造体的操作的入口是从context包的函数开始的,而后是通过ShoudBindWith函数对接binding包中的具体的解析对象。最初,通过不同的函数将申请中不同的参数解析到构造体上。如下图所示:
四、总结
本文解说了在gin框架中申请体的内容是如何绑定到对应构造体上的。同时剖析了在gin中不同的bind函数以及bindXXX函数之间的差别。在其余框架中其实也相似,因为在底层的http包中是按标准协议传递参数的,下层只是实现不同而已。
特地举荐:一个专一go我的项目实战、我的项目中踩坑教训及避坑指南、各种好玩的go工具的公众号:「Go学堂」,专一实用性,十分值得大家关注。关注送《100个go常见的谬误》pdf文档。