前言:
小编好几个月都没更新啦。注意力都在体验幸福甜蜜的的生活在。由于注意力被分散,在此期间,
耳机掉了两副,小米手环掉了两个,周围发生的事情间接性忽略掉了,恍然间回过神来已过去几个
月。蓦然回首时间过滴好快呀。得给宝子们来点干货
强类型语言
数据绑定
在强类型语言中,绑定参数分好几种类型。拿最使用广泛的Gin web 框架介绍
1、Bind 和 ShouldBind
Gin 的 Context 为请求数据绑定提供了两大类方法:在命名上以 Bind 为前缀和以 ShouldBind区分。这两大类方法在行为上有些差异。
类型 | 描述 |
---|---|
must | 条件必须要满足 |
should | 条件应该满足 |
Bind
方法会自动将 http status
设置为 400。而且不会返回更多的信息。由于存在,错误处理复杂,限制较多(仅仅支持常见类型),验证规则限制简单,可能存在安全风险等等在日常开发中几乎不建议使用bind 来绑定数据
ShouldBind、ShouldBindJSON 这些方法的区别是前者会自动根据 Header 头确定使用什么绑定器,如果团队内开发规范里约定了请求 Content-Type 都是 JSON 的话,直接选用后者更为合理。
在实际开发中,ShouldBind 自动根据Header 头确定使用什么绑定器使用最多。因为团队的约定对新加入的团队的人来说没看到约定的情况下,容易出现代码不兼容的问题。
var request struct {
Email string `form:"email" binding:"required"`
Name string `form:"name" binding:"required"`
}
// ShouldBind 常规绑定也可以兼容post get json 参数
if err := ctx.ShouldBind(&request); err != nil {
core.Response(ctx, gin.H{}, err)
return
}
// Content-Type 都是 JSON 的话,对于强类型语言来说,使用下面这段更合理,一般情况还是用上面这种。
if err := ctx.ShouldBindJson(&request); err != nil {
core.Response(ctx, gin.H{}, err)
return
}
2、单次绑定和多次绑定request body 数据
有了上面的绑定基础情况下,小编遇到了这样的一个问题。权限验证
中间件,在接收参数的时候使用的下面代码的接收参数的方式。接口的请求参数是Content-Type 都是 JSON 的类型的。
message := ctx.PostForm("message")
ids := ctx.QueryMap("ids")
message := ctx.GetQuery("message")
此时此刻,为了让接口绑定参数和中间件绑定参数,就会有二次绑定的数据的问题。小编楞是找了半天,原来强类型语言,几乎对类型都有做区分。不管是json get post request 类型每种类型都做了区分,连二次绑定都做了区分,不得不说,为了性能牺牲编写代码的体验。所以关键来了
无论是 Bind 还是 ShouldBind 类的绑定方法,都只能读取一次请求体进行绑定
可以使用ShouldBindBodyWith
来实现二次及多次绑定。那问题又来了,使用了ShouldBindBodyWith
绑定从一个参数被绑定开始,后面的绑定都得使用ShouldBindBodyWith
来绑定,有这样的限制才能实现多次绑定
if err := ctx.ShouldBindBodyWith(&request,binding.JSON); err != nil {
core.Response(ctx, gin.H{}, err)
return
}
到了这里基本上对参数绑定有了一定的了解。不同类型需要相互转换,不同的的场景需要不同的方法来实现。相对于弱类型语言PHP
来说,不管三七二一,一键全部接收,不管什么类型,一次绑定还是多次绑定也好,照单全收,这样的处理也间接导致弱类型语言在底层处理上需要兼容各种类型,性能也相对于强类型语言编译需要更多的内容空间和消耗更多的CPU资源。
3、通用类型绑定
在强类型语言中,接收参数的时候,常用结构体来绑定数据类型。每种结构体定义一种类型。而且首字母要大写。
type request struct {
Email string `form:"email" binding:"required"`
Name string `form:"name" binding:"required"`
Age int `form:"age" binding:"required"`
}
那么问题来了,要接收数据格式为json
数据格式怎么办。貌似单一的数据string int 等数据格式都不能满足了,需要嵌套结构体如下:
type Grouping struct {
ID int `json:"id"`
Remark string `json:"remark" default:""`
}
type Group struct {
Test1 []*Grouping `json:"test1"`
Test2 Grouping `json:"test2"`
Test3 string `json:"test3"`
Test4 int `json:"test4"`
}
那么问题又来了,这种类型是json 格式固定的情况下,那么需求有变动,就得更新代码新增结构体字段。增加一个结构体字段,就得重新编译一次。那没有接收通用类型的字段值。
接下来 interface
类型就派上用场了。interface
类型为通用类型,MySQL
数据库没有这种类型。还需要将interface
类型转成 json,string,int 这样的类型才能保存。所以在接收通用数据参数格式的时候,得借助MySQL第三方扩展库在标识,接收通用类型是 text string 还是json 类型
type UserGroupTask struct {
Test1 interface{} `json:"test1" form:"test1" gorm:"type:'json'"`
}
通过标识 gorm
标识,interface
类型为json
。这样在入MySQL数据库的时候,才能识别出是JSON 格式。
总结
上面介绍了强类型语言,需要对字段类型做转化、数据绑定类型指定等,在弱类型语言中在底层封装好了。
留下一个疑问,上面的代码接收通用格式,怎么在尽可能少写结果体的前提下,把json 格式的参数取出来做判断后,在入到数据库里去呢。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。