Gin源码分析 – Context之PostForm
1 介绍
对于表单数据的获取Gin也提供了一组方法,本文将对这组方法的使用以及源码进行详细的分析,下面的例子模拟一个最简单的登陆。
package main import ( "net/http" "github.com/gin-gonic/gin" ) func main() { r := gin.Default() r.POST("/login", func(c *gin.Context) { username := c.PostForm("username") password := c.PostForm("password") c.JSON(http.StatusOK, gin.H{ "username": username, "password": password, }) }) r.Run(":9999") }
通过curl发送POST请求,显示结果如下:
curl -d "username=TerryPro&password=123456" 127.0.0.1:9999/login {"password":"123456","username":"TerryPro"}
2 函数概述
Gin提供的PostForm函数与Query基本上一一对应的,具体情况见下表
Query方法 |
PostForm方法 |
说明 |
Query |
PostForm |
获取key对应的值,不存在返回空字符串 |
GetQuery |
GetPostForm |
获取key对应的值,并且返回bool标识,标识成功或者失败 |
QueryArray |
PostFormArray |
获取key对应的值,只是一个字符串数组,不存在返回空字符串数组 |
GetQueryArray |
GetPostFormArray |
获取key对应的值,并且返回bool标识,标识成功或者失败 |
QueryMap |
PostFormMap |
获取key对应的值,值是一个字符串map[string]string,不存在返回空 |
GetQueryMap |
GetPostFomMap |
获取key对应的值,值是一个字符串map[string]string,并且返回bool标识,标识成功或者失败 |
DefaultQuery |
DefaultPostForm |
key不存在时返回一个默认值 |
3 PostForm分析
func (c *Context) PostForm(key string) string { value, _ := c.GetPostForm(key) return value } func (c *Context) DefaultPostForm(key, defaultValue string) string { if value, ok := c.GetPostForm(key); ok { return value } return defaultValue } func (c *Context) GetPostForm(key string) (string, bool) { if values, ok := c.GetPostFormArray(key); ok { return values[0], ok } return "", false } func (c *Context) GetPostFormArray(key string) ([]string, bool) { c.initFormCache() if values := c.formCache[key]; len(values) > 0 { return values, true } return []string{}, false }
从上面的代码可以看出PostForm的调用方式和Query也是一致的:
(1)PostForm和DefaultPostForm内部调用GetPostForm;
(2)GetPostForm调用GetPostFormArray,Context中使用了另外一个变量formCache缓存PostForm参数,调用
Request.ParseMultipartForm完成参数的解析。
func (c *Context) initFormCache() { if c.formCache == nil { c.formCache = make(url.Values) req := c.Request if err := req.ParseMultipartForm(c.engine.MaxMultipartMemory); err != nil { if err != http.ErrNotMultipart { debugPrint("error on parse multipart form array: %v", err) } } c.formCache = req.PostForm } } type Context struct { // formCache use url.ParseQuery cached PostForm contains the parsed form data from POST, PATCH, // or PUT body parameters. formCache url.Values }
4 PostFormMap分析
// PostFormMap returns a map for a given form key. func (c *Context) PostFormMap(key string) map[string]string { dicts, _ := c.GetPostFormMap(key) return dicts } // GetPostFormMap returns a map for a given form key, plus a boolean value // whether at least one value exists for the given key. func (c *Context) GetPostFormMap(key string) (map[string]string, bool) { c.initFormCache() return c.get(c.formCache, key) }
(1)PostFormMap调用GetPostFormMap返回一个map[string]string;
(2)GetPostFormMap首先完成参数解析并进行缓存,然后调用get方式完成map的获取,这个函数在Query一文件已经分析过。
下面的例子给出了使用方法以及使用curl进行验证的结果。
r.POST("/loginMap", func(c *gin.Context) { params := c.PostFormMap("params") c.JSON(http.StatusOK, gin.H{ "params": params, }) })
curl -d "params[username]=TerryPro¶ms[password]=123456" 127.0.0.1:9999/loginMap {"params":{"password":"123456","username":"TerryPro"}}
5 小节
如果看过Query的分析则本文的内容还是相对简单的。