嗨,我想将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请求该情况下,用户可以指定可选参数Offset,Limit,SortBy,Asc,Username,First_Name,Last_Name,Status。
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)
但是我无法在GET请求中发送正文,所以解决方案是什么呢?而不是单独获取每个参数然后将其放入结构中?
GET
schema
该github.com/gorilla/schema包装正是为此而发明的。
github.com/gorilla/schema
您可以使用struct标记]来告诉如何将URL参数映射到struct字段,schema程序包会寻找"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包的情况下执行此操作。
[]string
Request.Form是一个map从string到的映射[]string(因为一个参数可能会在URL中多次列出:
Request.Form
map
string
Form url.Values
和url.Values:
url.Values
type Values map[string][]string
因此,例如,如果您的Filter结构如下所示:
Filter
type Filter struct { Offset []string `json:"offset"` Limit []string `json:"limit"` SortBy []string `json:"sortby"` // ..other fields }
您可以简单地使用该json软件包进行封送r.Form,然后将其解封到您的结构中:
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) }
此解决方案处理是否为同一参数名称提供了多个值。如果您不关心多个值,而只想要一个,则必须首先将“”转换r.Form为map单个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] }
然后您可以以相同的方式m将其编入Filter结构并将其编入结构。
m