如何将所有GET请求查询参数放入Go中的结构中?

How to get all GET request query parameters into a structure in Go?

嗨,我想将 get 查询参数转换为 Go 中的结构,例如我有这样的结构:

type Filter struct {
    Offset int64  `json:"offset"`
    Limit  int64  `json:"limit"`
    SortBy string `json:"sortby"`
    Asc    bool   `json:"asc"`

    //User specific filters
    Username   string `json:"username"`
    First_Name string `json:"first_name"`
    Last_Name  string `json:"last_name"`
    Status     string `json:"status"`
}

并且我有用户在发送 get 请求时可以指定的可选参数,它们是 OffsetLimitSortByAscUsername, First_Name, Last_Name, Status.

如果这些参数在正文中发送,那么我会这样做:

b, err := ioutil.ReadAll(r.Body)
if err != nil {

    log.WithFields(logFields).Errorf("Reading Body Message:failed:%v", err)

    return
}

var filter Filter
err = json.Unmarshal(b, &filter)

但我无法在 GET 请求中发送正文,那么解决方案是什么,而不是单独获取每个参数,然后将它们放入结构中?

使用大猩猩的schema

github.com/gorilla/schema 包就是为此发明的。

您可以使用 struct tags 告诉如何将 URL 参数映射到结构字段,schema 包查找 "schema" 标签键。

使用它:

import "github.com/gorilla/schema"

type Filter struct {
    Offset int64  `schema:"offset"`
    Limit  int64  `schema:"limit"`
    SortBy string `schema:"sortby"`
    Asc    bool   `schema:"asc"`

    //User specific filters
    Username   string `schema:"username"`
    First_Name string `schema:"first_name"`
    Last_Name  string `schema:"last_name"`
    Status     string `schema:"status"`
}

func MyHandler(w http.ResponseWriter, r *http.Request) {
    if err := r.ParseForm(); err != nil {
        // Handle error
    }

    filter := new(Filter)
    if err := schema.NewDecoder().Decode(filter, r.Form); err != nil {
        // Handle error
    }

    // Do something with filter
    fmt.Printf("%+v", filter)
}

使用 json

编组和解组

请注意,schema 包也会尝试将参数值转换为字段类型。

如果结构只包含 []string 类型的字段(或者您愿意做出这种妥协),您可以在没有 schema 包的情况下做到这一点。

Request.Form 是一个 map,从 string 映射到 []string(因为一个参数可能在 URL 中多次列出:

Form url.Values

url.Values

type Values map[string][]string

例如,如果您的 Filter 结构如下所示:

type Filter struct {
    Offset []string `json:"offset"`
    Limit  []string `json:"limit"`
    SortBy []string `json:"sortby"`
    // ..other fields
}

您可以简单地使用 json 包编组 r.Form,然后将其解组到您的结构中:

func MyHandler(w http.ResponseWriter, r *http.Request) {
    if err := r.ParseForm(); err != nil {
        // Handle error
    }
    data, err := json.Marshal(r.Form)
    if err != nil {
        // Handle error
    }
    filter := new(Fiter)
    if err = json.Unmarshal(data, filter); err != nil {
        // Handle error
    }
    fmt.Printf("%+v", filter)
}

如果为同一参数名称提供了多个值,此解决方案会处理。如果您不关心多个值而只想要一个,则首先必须 "transform" r.Form 到具有单个 string 值而不是 [=22= 的 map ].

它可能是这样的:

type Filter struct {
    Offset string `json:"offset"`
    Limit  string `json:"limit"`
    SortBy string `json:"sortby"`
    // ..other fields
}

// Transformation from map[string][]string to map[string]string:
m := map[string]string{}
for k, v := range r.Form {
    m[k] = v[0]
}

然后您可以将 m 编组并以相同的方式将其解组到 Filter 结构中。

对于 Echo 框架,您可以将查询字符串绑定到类似此示例代码的结构。

type Filter struct {
    Offset int64  `query:"offset"`
    Limit  int64  `query:"limit"`
    SortBy string `query:"sortby"`
    Asc    bool   `query:"asc"`

    //User specific filters
    Username   string `query:"username"`
    First_Name string `query:"first_name"`
    Last_Name  string `query:"last_name"`
    Status     string `query:"status"`
}

query := new(Filter)
if err := c.Bind(query); err != nil {
    // handle error here
}

使用ggicci/httpin

免责声明:我是这个包的创建者和维护者。

httpin帮你轻松解码来自

的HTTP请求数据
  • 查询参数,例如?name=john&is_member=true
  • Headers,例如Authorization: xxx
  • 表单数据,例如username=john&password=******
  • JSON/XML Body,例如POST {"name":"john"}
  • 路径变量,例如/users/{username}
  • 文件上传

如何使用?

type ListUsersInput struct {
    Page     int  `in:"query=page"`
    PerPage  int  `in:"query=per_page"`
    IsMember bool `in:"query=is_member"`
}

func ListUsers(rw http.ResponseWriter, r *http.Request) {
    input := r.Context().Value(httpin.Input).(*ListUsersInput)

    if input.IsMember {
        // Do sth.
    }
    // Do sth.
}

httpin 是: