5.07 Context-处理输入之表单输入
本节课工程路径如下:
注:相比于02-bindJSON
,有如下变更:
删除了演示用的
config.go
删除了
HTTPServer
结构体中的useNumber
和disallowUnknownFields
字段(这两个字段也是上节课演示用的)
PART1. http.Request.Form
与http.Request.PostForm
的区别
http.Request.Form
与http.Request.PostForm
的区别http.Request.Form
:可以接收URL中的参数以及HTTP动词为PATCH
、POST
、PUT
时的表单数据http.Request.PostForm
:只能接收HTTP动词为PATCH
、POST
、PUT
时的表单数据不管使用以上二者中的哪一种,都要先调用
http.Request.ParseForm()
解析表单数据后,这两个字段才有数据
示例:
请求如下图示:
可以看到,URL中的参数为:
name=zhangsan
age=18
表单数据中的参数为:
name=lisi
gender=male
响应如下图示:
可以看到:
http.Request.Form
既可以收到URL中的参数,也可以接收到表单中的参数http.Request.PostForm
只能接收到表单中的参数注意,二者的返回值类型都是
url.Values
,实际上就是map[string][]string
二者最核心的区别在于:
http.Request.Form
:基本上可以认为能够拿到所有的表单数据http.Request.PostForm
:只能拿到ContentType为x-www-form-urlencoded
时的表单数据
不建议使用表单的方式进行通信,而是建议在Body中写入JSON或Protobuf的方式进行通信.因为在数据结构较为复杂的场景下,使用使用JSON或Protobuf比使用Form的可读性要更高.因此在可选择的前提下,尽可能采用Body中中写入JSON或Protobuf的方式进行通信.
PART2. 实现Context.FormValue()
方法
Context.FormValue()
方法2.1 完全自行实现
注意,这里只返回同名参数中的第1个值,是参照了http.Request.FormValue()
方法的返回.
这里不建议如下方式的实现:
不建议按此方式返回,因为大部分场景下表单中的键都是唯一的.还是上节课提到的观点:为了支持一个小众的需求,反而会影响到大部分主流用户的使用,那么就不要支持这个小众的需求.
2.2 依赖原生API的实现
推荐使用这种实现,因为这种实现的语义和原生API语义相同.
甚至可以不要前边对于http.Request.ParseForm()
方法返回值的错误判断部分.但不建议这么做.因为虽然http.Request.ParseMultipartForm()
方法会进行解析并返回解析错误,但它返回的错误被http.Request.FormValue()
方法在调用时给丢弃掉了,没有处理.所以最好还是主动自己解析一下,以防万一.
PART3. 相关问题
3.1 多次调用Context.FormValue()
方法是否会造成重复解析?
Context.FormValue()
方法是否会造成重复解析?答案是不会的.因为http.Request.ParseForm()
方法的调用是幂等的.证据如下:
这里有一种观点认为在GIN中,gin.Context.formCache
字段是没有必要设计的,因为原生的http.Request.Form
和http.Request.PostForm
字段本身就起到了缓存的效果
3.2 是否需要提供返回其他数据类型的API?
例如:根据给定的key
,返回一个int64
类型数据的方法.其实现如下:
那么问题来了:要不要实现这种(注意是这种不是这个)API?
如果要提供的话,至少要提供3个:
获取表单中给定键的值,并将该值转换为
int64
类型返回获取表单中给定键的值,并将该值转换为
uint64
类型返回获取表单中给定键的值,并将该值转换为
float64
类型返回
用户拿到这3种类型的数据,再自己向下转型(强制类型转换).
但其实不需要提供.这里因为其他处理输入的API也会遇到类似的问题,后边统一讲这个事情.
Last updated