gin获取get和post以及json所有参数获取

描述:

  1. http接口,一般有如下几种传参:get、post、 post application/json 的模式,当然还有post传xml模式,只是用的人比较少
  2. 一般我们在使用中间件的时候,需要把所有的参数给获取到,然后进行加密验签。需要对所有的参数进行统一验证。

问题

  1. 我在使用gin框架的context的时候,发现有如下方法:ShouldBind 可用于GET的绑定参数,ShouldBindJSON和ShouldBind一样,只是增加了一个格式参数,ShouldBindWith同json。后发现ShouldBind类型的函数只能使用一次,第二次再绑定的时候就无法使用了,
    如:
    var tmpParams = make(map[string]string)
    err2 := ctx.ShouldBind(&tmpParams)
    if err2 != nil {
       fmt.Println(err2)
    }
    fmt.Printf("-----tmpParams: %v \n",tmpParams )
    var tmpParams2 = make(map[string]string)
    err3 := ctx.ShouldBind(&tmpParams2)
    if err3 != nil {
       fmt.Println(err3)
    }
    fmt.Printf("-----tmpParams2: %v \n",tmpParams2 )

打印后发现,tmpParams正常,tmpParams2没有值。
这对于我们写中间件的人来说是绝对不能接受的,不能因为中间件取值了,其它接口内部就无法使用ShouldBind来接受参数。

解决问题

最终发现我的github.com/gin-gonic/gin
版本过低,是1.6.3版本,然后升级到1.8.1发现,可以重复绑定了问题解决

整理了下代码

package RequestParse

import (
    "fmt"
    "github.com/gin-gonic/gin"
    "github.com/gin-gonic/gin/binding"
    "github.com/sirupsen/logrus"
    "strings"
    "sync"
)

type RequestHttp struct {
    ctx *gin.Context
    Params map[string]interface{}
    lock sync.Mutex
}

func Instance(ctx *gin.Context) *RequestHttp  {
    return &RequestHttp{
        ctx: ctx,
        Params: map[string]interface{}{},
    }
}

//获取默认参数列表
func (r *RequestHttp) GetDefaultParams() map[string]interface{} {
    ctx := r.ctx
    method := ctx.Request.Method
    url := ctx.Request.URL.Path
    return map[string]interface{}{
        "method": method,
        "url": url,
        "remoteAddr": r.GetRemoteAddr(),
        "params": r.RequestParams(),
        "requestID": r.GetHeaderByKey("request-id"),
        "status": ctx.Writer.Status(),
        "userAgent": ctx.GetHeader("User-Agent"),
    }
}

//获取kname
func (r *RequestHttp) GetHeaderByKey(kname string) string  {
    return r.ctx.Request.Header.Get(kname)
}

//获取remoteAddr
func (r *RequestHttp) GetRemoteAddr() string {
    remoteAddr := r.ctx.Request.Header.Get("Remote_addr")//远程调用
    if remoteAddr == "" {
        remoteAddr = r.ctx.Request.Header.Get("X-Forward-For")
    }
    return remoteAddr
}

//获取参数集合
func (r *RequestHttp) RequestParams() string {
    ctx := r.ctx
    bindParams := map[string]interface{}{}
    if ctx.Request.Method == "POST" {
        contextType := ctx.Request.Header.Get("Content-Type")
        if contextType == "application/json" {
            err := ctx.ShouldBindBodyWith(&bindParams, binding.JSON)
            if err != nil {//报错
                logrus.Errorf("nyx_request_mid_error %v,err: %v \n", bindParams, err)
                return ""
            }
            if len(bindParams) > 0 {
                for k, v :=  range bindParams {
                    r.Add(k, v)
                }
            }
        } else {
            _ = ctx.Request.ParseMultipartForm(32 << 20)
            if len(ctx.Request.PostForm) > 0 {
                for k, v := range ctx.Request.PostForm {
                    r.Add(k, v[0])
                }
            }
        }
    } else {
        var tmpParams = make(map[string]string)
        err2 := ctx.ShouldBind(&tmpParams)
        if err2 != nil {
            fmt.Println(err2)
            logrus.Errorf("nyx_request_mid_error %v,err: %v \n", bindParams, err2)
            return ""
        }
        for k, v := range tmpParams {
            r.Add(k, v)
        }
    }
    fmt.Printf("------params:%v \n",r.JoinParamsStr())
    return r.JoinParamsStr()
}

//添加参数
func (r *RequestHttp) AddParams(m map[string]interface{})  {
    if len(m) <= 0 {
        return
    }
    for k, v :=  range m {
        r.Add(k, v)
    }
}

func (r *RequestHttp) JoinParamsStr() string {
    var params []string
    if len(r.Params) > 0 {
        for k,v := range r.Params {
            params = append(params, fmt.Sprintf("%s=%v", k, v))
        }
    }

    return strings.Join(params, "&")
}

//添加参数
func (r *RequestHttp) Add(key string, value interface{})  {
    r.lock.Lock()
    r.Params[key] = value
    r.lock.Unlock()
}

//删除参数
func (r *RequestHttp) Delete(key string)  {
    r.lock.Lock()
    if _,ok := r.Params[key]; ok {
        delete(r.Params, key)
    }
    r.lock.Unlock()
}

以上代码包含、post、get、以及json的方式的参数获取方法。中间件封装的时候可以借鉴。

本作品采用《CC 协议》,转载必须注明作者和本文链接
讨论数量: 1

你这还是没解决啊!

原因:ShouldBindJSON在调用过一次之后context.request.body.sawEOF的值是false导致

解决方案:可以使用ShouldBindBodyWith进行多次绑定

_ = c.ShouldBindBodyWith(&pageInfo, binding.JSON)
_ = c.ShouldBindBodyWith(&reqParentId, binding.JSON)
9个月前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!