将 URL.Query(切片映射)转换为 struct golang
Posted
技术标签:
【中文标题】将 URL.Query(切片映射)转换为 struct golang【英文标题】:Convert URL.Query (map of slices) to struct golang 【发布时间】:2017-03-26 16:18:22 【问题描述】:如果能从标准库 URL.Query() 直接映射到结构体,那就太棒了。
Query()
返回如下地图:
map[a:[aaaa] b:[bbbb] c:[cccc]]
结构如下:
type Thing struct
A string
B string
C string
我不知道为什么 URL.Query 会返回一个包含数组元素的映射。 (嗯..我知道why 但GET
不太可能有重复的参数)
【问题讨论】:
一个 GET 是 -- 不太可能 -- 可以有重复的参数。在这种情况下,它被转换为一个值切片。你看过 gorilla.schema 包吗?我相信它可以胜任。 在我的情况下,我会很好并且热衷于在重复的情况下触发一个异常。我查看了 gorilla.schema,太棒了!谢谢。 【参考方案1】:请在下面找到直接在 golang 结构中解析 get 查询参数然后将结构作为响应发送回来的完整示例
package main
import (
"log"
"net/http"
"encoding/json"
"github.com/gorilla/schema"
)
var decoder = schema.NewDecoder()
type EmployeeStruct struct
MemberId string `schema:"memberId"`
ActivityType string `schema:"activityType"`
BusinessUnitCode int `schema:"businessUnitCode"`
func GetEmployee(w http.ResponseWriter, r *http.Request)
var employeeStruct EmployeeStruct
err := decoder.Decode(&employeeStruct, r.URL.Query())
if err != nil
log.Println("Error in GET parameters : ", err)
else
log.Println("GET parameters : ", employeeStruct)
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(employeeStruct)
func main()
mux := http.NewServeMux()
mux.HandleFunc("/GetEmployee", GetEmployee)
log.Fatal(http.ListenAndServe(":8080", mux))
执行和测试的步骤(假设您将上述代码保存在 employee.go 中):
第一步:运行employee.go
第二步:在浏览器中打开http://localhost:8080/GetEmployee?memberId=123&activityType=Call&businessUnitCode=56
第 3 步:您应该在浏览器窗口中得到以下响应
"MemberId": "123",
"ActivityType": "Call",
"BusinessUnitCode": 56
第 4 步:在控制台上,您应该会看到以下内容
GET parameters : 123 Call 56
【讨论】:
【参考方案2】:示例:
filters="reference":["docker.io/library/alpine:latest"]
需要将网址编码为:
filters=%7B%22reference%22%3A%5B%22docker.io%2Flibrary%2Falpine%3Alatest%22%5D%7D
并且可以使用"github.com/gorilla/schema"
query := struct
All bool
Filters map[string][]string `schema:"filters"`
Digests bool
Filter string
decoder := schema.NewDecoder()
decoder.Decode(&query, r.URL.Query())
【讨论】:
【参考方案3】:正如@mh-cbon 所指出的,gorilla schema 是这里的终极解决方案。
而不是从 URL 属性中获取 queryParams。
func handleRequest(w http.ResponseWriter, r *http.Request)
queryString := r.URL.Query()
//...parsing the Values -> map[string][]string
gorilla 模式的方法是将r.PostForm
发送到解码函数。
func handleRequest(w http.ResponseWriter, r *http.Request)
err := decoder.Decode(person, r.PostForm)
//...using reflect each struct's property can be called using
// the PostForm(url string, data url.Values) signature
fmt.Print(person.GoodJobGorilla)
【讨论】:
【参考方案4】:我写了一个 Go 包 ggicci/httpin 专门用于解决这个问题。不仅用于查询,还可以解码来自 HTTP 标头的数据。这是一个例子:
type Authorization struct
// Decode from multiple sources, the former with higher priority
Token string `in:"form=access_token;header=x-api-token;required"`
type Pagination struct
Page int `in:"form=page"`
// Decode from multiple keys in the same source, the former with higher priority
PerPage int `in:"form=per_page,page_size"`
type ListUsersInput struct
Gender string `in:"form=gender"`
AgeRange []int `in:"form=age_range"`
IsMember bool `in:"form=is_member"`
Pagination // Embedded field works
Authorization // Embedded field works
func ListUsers(rw http.ResponseWriter, r *http.Request)
inputInterface, err := httpin.New(ListUsersInput).Decode(r)
if err != nil
// Error occurred, `err` can be type of *httpin.InvalidFieldError
// Do sth.
return
input := interfaceInput.(*ListUsersInput)
// Do sth.
我确实希望这个库可以节省大家用 Go 编写 API 的时间。
【讨论】:
【参考方案5】:你可以使用Echo的优雅包。
我写了一些代码作为例子,带有不言自明的cmets
package main
import (
"log"
"github.com/labstacks/echo"
)
// Declare your struct with form: "" tag
type Employee struct
MemberId string `form:"memberId"`
ActivityType string `form:"activityType"`
BusinessUnitCode int `form:"businessUnitCode"`
// Your handlers should look like this method
// Which takes an echo.Context and returns an error
func GetEmployee(ctx echo.Context) error
var employee Employee
// With Bind, you can get the Post Body or query params from http.Request
// that is wrapped by echo.Context here
if err := ctx.Bind(&employee);err != nil
return err
// now you can use your struct , e.g
return ctx.json(200, employee.MemberId)
// now use the handler in your main function or anywhere you need
func main()
e := echo.New()
e.Get("/employee", GetEmployee)
log.Fatal(e.Start(":8080"))
【讨论】:
我认为这是相关文档pkg.go.dev/github.com/labstack/echo/v4#DefaultBinder.Bind 的正确链接但是,事实是,IDK,上下文使用的 Binder 和其他。所以我认为它可能存在更好的链接。【参考方案6】:只需将字符串解析为 URL,然后您就可以使用 lib github.com/gorilla/schema
对其进行解析:)
// Example to parse querystring to struct
package main
import (
"log"
"net/url"
"github.com/gorilla/schema"
)
type URLParams struct
Code string `schema:"code"`
State string `schema:"state"`
func main()
var (
params URLParams
decoder = schema.NewDecoder()
)
p := "https://www.redirect-url.com?code=CODE&state=RANDOM_ID"
u, _ := url.Parse(p)
err := decoder.Decode(¶ms, u.Query())
if err != nil
log.Println("Error in Decode parameters : ", err)
else
log.Printf("Decoded parameters : %#v\n", params)
https://go.dev/play/p/CmuPhdKh6Yg
【讨论】:
以上是关于将 URL.Query(切片映射)转换为 struct golang的主要内容,如果未能解决你的问题,请参考以下文章