参数获取
源码路径:github.com/gin-gonic/gin/context.go
URL
func (c *Context) Param(key string) string
eg:
router.GET("/user/:id", func(c *gin.Context) {// // a GET request to /user/johnid := c.Param("id") // id == "john"})
query
// It is shortcut for `c.Request.URL.Query().Get(key)`// GET /path?id=1234&name=Manu&value=// c.Query("id") == "1234"// c.Query("name") == "Manu"// c.Query("value") == ""// c.Query("wtf") == ""func (c *Context) Query(key string) string {value, _ := c.GetQuery(key)return value}
其他方式query
func (c *Context) QueryArray(key string) []string {values, _ := c.GetQueryArray(key)return values}func (c *Context) getQueryCache() {if c.queryCache == nil {c.queryCache = c.Request.URL.Query()}}// GetQueryArray returns a slice of strings for a given query key, plus// a boolean value whether at least one value exists for the given key.func (c *Context) GetQueryArray(key string) ([]string, bool) {c.getQueryCache()if values, ok := c.queryCache[key]; ok && len(values) > 0 {return values, true}return []string{}, false}// QueryMap returns a map for a given query key.func (c *Context) QueryMap(key string) map[string]string {dicts, _ := c.GetQueryMap(key)return dicts}// GetQueryMap returns a map for a given query key, plus a boolean value// whether at least one value exists for the given key.func (c *Context) GetQueryMap(key string) (map[string]string, bool) {c.getQueryCache()return c.get(c.queryCache, key)}
PostForm
// PostForm returns the specified key from a POST urlencoded form or multipart form// when it exists, otherwise it returns an empty string `("")`.func (c *Context) PostForm(key string) string {value, _ := c.GetPostForm(key)return value}// DefaultPostForm returns the specified key from a POST urlencoded form or multipart form// when it exists, otherwise it returns the specified defaultValue string.// See: PostForm() and GetPostForm() for further information.func (c *Context) DefaultPostForm(key, defaultValue string) string {if value, ok := c.GetPostForm(key); ok {return value}return defaultValue}// GetPostForm is like PostForm(key). It returns the specified key from a POST urlencoded// form or multipart form when it exists `(value, true)` (even when the value is an empty string),// otherwise it returns ("", false).// For example, during a PATCH request to update the user's email:// email=mail@example.com --> ("mail@example.com", true) := GetPostForm("email") // set email to "mail@example.com"// email= --> ("", true) := GetPostForm("email") // set email to ""// --> ("", false) := GetPostForm("email") // do nothing with emailfunc (c *Context) GetPostForm(key string) (string, bool) {if values, ok := c.GetPostFormArray(key); ok {return values[0], ok}return "", false}// PostFormArray returns a slice of strings for a given form key.// The length of the slice depends on the number of params with the given key.func (c *Context) PostFormArray(key string) []string {values, _ := c.GetPostFormArray(key)return values}func (c *Context) getFormCache() {if c.formCache == nil {c.formCache = make(url.Values)req := c.Requestif 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}}// GetPostFormArray returns a slice of strings for a given form key, plus// a boolean value whether at least one value exists for the given key.func (c *Context) GetPostFormArray(key string) ([]string, bool) {c.getFormCache()if values := c.formCache[key]; len(values) > 0 {return values, true}return []string{}, false}// 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.getFormCache()return c.get(c.formCache, key)}// get is an internal method and returns a map which satisfy conditions.func (c *Context) get(m map[string][]string, key string) (map[string]string, bool) {dicts := make(map[string]string)exist := falsefor k, v := range m {if i := strings.IndexByte(k, '['); i >= 1 && k[0:i] == key {if j := strings.IndexByte(k[i+1:], ']'); j >= 1 {exist = truedicts[k[i+1:][:j]] = v[0]}}}return dicts, exist}
上传
// FormFile returns the first file for the provided form key.func (c *Context) FormFile(name string) (*multipart.FileHeader, error) {if c.Request.MultipartForm == nil {if err := c.Request.ParseMultipartForm(c.engine.MaxMultipartMemory); err != nil {return nil, err}}f, fh, err := c.Request.FormFile(name)if err != nil {return nil, err}f.Close()return fh, err}// MultipartForm is the parsed multipart form, including file uploads.func (c *Context) MultipartForm() (*multipart.Form, error) {err := c.Request.ParseMultipartForm(c.engine.MaxMultipartMemory)return c.Request.MultipartForm, err}// SaveUploadedFile uploads the form file to specific dst.func (c *Context) SaveUploadedFile(file *multipart.FileHeader, dst string) error {src, err := file.Open()if err != nil {return err}defer src.Close()out, err := os.Create(dst)if err != nil {return err}defer out.Close()_, err = io.Copy(out, src)return err}
参数校验/binding
源码地址github.com/gin-gonic/gin/binding/binding.go
提供的默认的类型
var (JSON = jsonBinding{}XML = xmlBinding{}Form = formBinding{}Query = queryBinding{}FormPost = formPostBinding{}FormMultipart = formMultipartBinding{}ProtoBuf = protobufBinding{}MsgPack = msgpackBinding{}YAML = yamlBinding{}Uri = uriBinding{}Header = headerBinding{})
定义需要实现的接口
type Binding interface {Name() stringBind(*http.Request, interface{}) error}// BindingBody adds BindBody method to Binding. BindBody is similar with Bind,// but it reads the body from supplied bytes instead of req.Body.type BindingBody interface {BindingBindBody([]byte, interface{}) error}
例如json的实现类
type jsonBinding struct{}func (jsonBinding) Name() string {return "json"}func (jsonBinding) Bind(req *http.Request, obj interface{}) error {if req == nil || req.Body == nil {return fmt.Errorf("invalid request")}return decodeJSON(req.Body, obj)}func (jsonBinding) BindBody(body []byte, obj interface{}) error {return decodeJSON(bytes.NewReader(body), obj)}func decodeJSON(r io.Reader, obj interface{}) error {decoder := json.NewDecoder(r)if EnableDecoderUseNumber {decoder.UseNumber()}if EnableDecoderDisallowUnknownFields {decoder.DisallowUnknownFields()}if err := decoder.Decode(obj); err != nil {return err}return validate(obj)}
校验
/ Bind checks the Content-Type to select a binding engine automatically,// Depending the "Content-Type" header different bindings are used:// "application/json" --> JSON binding// "application/xml" --> XML binding// otherwise --> returns an error.// It parses the request's body as JSON if Content-Type == "application/json" using JSON or XML as a JSON input.// It decodes the json payload into the struct specified as a pointer.// It writes a 400 error and sets Content-Type header "text/plain" in the response if input is not valid.func (c *Context) Bind(obj interface{}) error {b := binding.Default(c.Request.Method, c.ContentType())return c.MustBindWith(obj, b)}// BindJSON is a shortcut for c.MustBindWith(obj, binding.JSON).func (c *Context) BindJSON(obj interface{}) error {return c.MustBindWith(obj, binding.JSON)}// MustBindWith binds the passed struct pointer using the specified binding engine.// It will abort the request with HTTP 400 if any error occurs.// See the binding package.func (c *Context) MustBindWith(obj interface{}, b binding.Binding) error {if err := c.ShouldBindWith(obj, b); err != nil {c.AbortWithError(http.StatusBadRequest, err).SetType(ErrorTypeBind) // nolint: errcheckreturn err}return nil}// ShouldBindWith binds the passed struct pointer using the specified binding engine.// See the binding package.func (c *Context) ShouldBindWith(obj interface{}, b binding.Binding) error {return b.Bind(c.Request, obj)}
