英文:
Convert URL.Query (map of slices) to struct golang
问题
从标准库的URL.Query()到一个结构体的直接映射会很棒。
Query() 返回一个类似于以下的映射:
map[a:[aaaa] b:[bbbb] c:[cccc]]
结构体如下所示:
type Thing struct {
    A    string
    B    string
    C    string
}
- 我不知道为什么URL.Query返回一个包含数组元素的映射(嗯...我知道为什么,但是一个
GET请求不太可能有重复的参数) 
英文:
It would be awesome to have a straight forward mapping from the standard library URL.Query() to an struct.
Query() returns a map like:
map[a:[aaaa] b:[bbbb] c:[cccc]]
The struct looks like:
type Thing struct {
    A    string
    B    string
    C    string
}
- I've no idea why URL.Query returns a map with array elements inside tough. (well.. I know why but a 
GETis not likely to have duplicated params) 
答案1
得分: 14
请查看以下完整示例,该示例演示了如何直接在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):
步骤1:运行命令 go run employee.go
步骤2:在浏览器中打开链接 http://localhost:8080/GetEmployee?memberId=123&activityType=Call&businessUnitCode=56
步骤3:你应该在浏览器窗口中看到以下响应:
{
    "MemberId": "123",
    "ActivityType": "Call",
    "BusinessUnitCode": 56
}
步骤4:在控制台上你应该看到以下输出:
GET parameters: {123 Call 56}
英文:
Please find below the complete example of parsing get query params directly in a golang struct and then sending the struct back as response
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))
}
Steps to execute & Test (Assuming you are saving above code in employee.go) :
Step 1 : go run employee.go
Step 2 : Open in browser http://localhost:8080/GetEmployee?memberId=123&activityType=Call&businessUnitCode=56
Step 3 : You should get below response in browser window
{
    "MemberId": "123",
    "ActivityType": "Call",
    "BusinessUnitCode": 56
}
Step 4 : On console you should see below
GET parameters :  {123 Call 56}
答案2
得分: 3
示例:
filters={"reference":["docker.io/library/alpine:latest"]}
需要进行URL编码:
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())
英文:
example:
filters={"reference":["docker.io/library/alpine:latest"]}
need url encode to:
filters=%7B%22reference%22%3A%5B%22docker.io%2Flibrary%2Falpine%3Alatest%22%5D%7D
and could use "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
得分: 2
如@mh-cbon所指出的,gorilla schema是这里的终极解决方案。
而不是从URL属性中获取queryParams。
func handleRequest(w http.ResponseWriter, r *http.Request) {
    queryString := r.URL.Query()
    //...解析Values -> map[string][]string
}
gorilla schema的方法是将r.PostForm传递给解码函数。
func handleRequest(w http.ResponseWriter, r *http.Request) {
    err := decoder.Decode(person, r.PostForm)
    //...使用反射可以调用每个结构体的属性,使用PostForm(url string, data url.Values)签名
    
    fmt.Print(person.GoodJobGorilla)
}
英文:
As pointed out by @mh-cbon gorilla schema is the ultimate solution here.
Instead for obtaining the queryParams from the URL attribute.
func handleRequest(w http.ResponseWriter, r *http.Request) {
    queryString := r.URL.Query()
    //...parsing the Values -> map[string][]string
}
The approach of gorilla schema is to ship r.PostForm to the decode function.
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
得分: 1
免责声明:我是这个包的创建者和维护者。
httpin帮助您轻松解码HTTP请求数据,包括:
- 查询参数,例如
?name=john&is_member=true - 头部信息,例如
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具有以下特点:
- 文档完善:请参阅https://ggicci.github.io/httpin/
 - 经过充分测试:覆盖率超过98%
 - 开放集成:与net/http,go-chi/chi,gorilla/mux,gin-gonic/gin等集成
 - 可扩展(高级功能):通过添加自定义指令。详细信息请阅读httpin - custom directives
 - 被提及的很棒:https://github.com/avelino/awesome-go#forms
 
英文:
Using ggicci/httpin
Disclaimer: I'm the creator and maintainer of this package.
httpin helps you easily decoding HTTP request data from
- Query parameters, e.g. 
?name=john&is_member=true - Headers, e.g. 
Authorization: xxx - Form data, e.g. 
username=john&password=****** - JSON/XML Body, e.g. 
POST {"name":"john"} - Path variables, e.g. 
/users/{username} - File uploads
 
How to use?
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 is:
- well documented: at https://ggicci.github.io/httpin/
 - well tested: coverage over 98%
 - open integrated: with net/http, go-chi/chi, gorilla/mux, gin-gonic/gin, etc.
 - extensible (advanced feature): by adding your custom directives. Read httpin - custom directives for more details.
 - awesome mentioned: https://github.com/avelino/awesome-go#forms
 
答案5
得分: 1
只需将字符串解析为URL,然后可以使用github.com/gorilla/schema库进行解析 ![]()
// 解析查询字符串到结构体的示例
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("解码参数时出错:", err)
	} else {
		log.Printf("解码后的参数:%#v\n", params)
	}
}
https://go.dev/play/p/CmuPhdKh6Yg
英文:
Just parse the string to URL and after you can use the lib github.com/gorilla/schema to parse it ![]()
// 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(&params, u.Query())
	if err != nil {
		log.Println("Error in Decode parameters : ", err)
	} else {
		log.Printf("Decoded parameters : %#v\n", params)
	}
}
答案6
得分: 1
如果有人正在使用Echo,query结构标签将对这种情况非常有用。
示例结构体
type struct Name {
    FirstName string `query:"first_name"`
    LastName string `query:"last_name"`
}
示例查询参数
?first_name="shahriar"&last_name="sazid"
代码
var name Name
err := c.Bind(&name); if err != nil {
    return c.String(http.StatusBadRequest, "bad request")
}
英文:
If anyone is using Echo, query struct tag will be useful for this case.
Example Struct
type struct Name {
    FirstName string `query:"first_name"`
    LastName string `query:"last_name"`
}
Example Query Param
?first_name="shahriar"&last_name="sazid"
Code
var name Name
err := c.Bind(&name); if err != nil {
    return c.String(http.StatusBadRequest, "bad request")
}
答案7
得分: 0
你可以使用Echo的graceful包。
我写了一些代码作为示例,并添加了自解释的注释
package main
import (
    "log"
    "github.com/labstack/echo"
)
// 使用form:""标签声明你的结构体
type Employee struct {
    MemberId         string `form:"memberId"`
    ActivityType     string `form:"activityType"`
    BusinessUnitCode int    `form:"businessUnitCode"`
}
// 你的处理函数应该像这个方法一样
// 接收一个echo.Context并返回一个错误
func GetEmployee(ctx echo.Context) error {
    var employee Employee
    // 使用Bind方法,你可以从echo.Context中获取HTTP请求的Post Body或查询参数
    if err := ctx.Bind(&employee); err != nil {
        return err
    }
    // 现在你可以使用你的结构体,例如
    return ctx.JSON(200, employee.MemberId)
}
// 现在在你的main函数或任何需要的地方使用处理函数
func main() {
    e := echo.New()
    e.GET("/employee", GetEmployee)
    log.Fatal(e.Start(":8080"))
}
英文:
You can use the graceful package of Echo.
I write some codes as an example, with self-explanatory comments
 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"))
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论