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

use*_*204 6 struct http go query-parameters

嗨我想将查询参数转换为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"`
}
Run Code Online (Sandbox Code Playgroud)

我有一个发送GET请求该情况下,用户可以指定可选参数Offset,Limit,SortBy,Asc,Username,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)
Run Code Online (Sandbox Code Playgroud)

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

icz*_*cza 5

使用大猩猩的schema

github.com/gorilla/schema包装是为此而发明的.

您可以使用struct标签来告诉如何将URL参数映射到struct字段,该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)
}
Run Code Online (Sandbox Code Playgroud)

使用编组和解编 json

请注意,该schema包还将尝试将参数值转换为字段的类型.

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

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

Form url.Values
Run Code Online (Sandbox Code Playgroud)

而且url.Values:

type Values map[string][]string
Run Code Online (Sandbox Code Playgroud)

例如,如果你的Filter结构看起来像这样:

type Filter struct {
    Offset []string `json:"offset"`
    Limit  []string `json:"limit"`
    SortBy []string `json:"sortby"`
    // ..other fields
}
Run Code Online (Sandbox Code Playgroud)

您可以简单地使用该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)
}
Run Code Online (Sandbox Code Playgroud)

此解决方案处理是否为同一参数名称提供了多个值.如果你不关心多个值而你只想要一个,那么首先必须"转换" r.Formmap单个string值而不是[]string.

这是它的样子:

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]
}
Run Code Online (Sandbox Code Playgroud)

然后你可以用同样的方式m编组和解组到Filter结构中.