【问题标题】:Convert URL.Query (map of slices) to struct golang将 URL.Query(切片映射)转换为 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 会返回一个包含数组元素的映射。 (嗯..我知道whyGET 不太可能有重复的参数)

【问题讨论】:

  • 一个 GET 是 -- 不太可能 -- 可以有重复的参数。在这种情况下,它被转换为一个值切片。你看过 gorilla.schema 包吗?我相信它可以胜任。
  • 在我的情况下,我会很好并且热衷于在重复的情况下触发一个异常。我查看了 gorilla.schema,太棒了!谢谢。

标签: go struct


【解决方案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"))
          }
          

          【讨论】:

          【解决方案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(&params, 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

          【讨论】:

            猜你喜欢
            • 2021-08-18
            • 1970-01-01
            • 1970-01-01
            • 2016-11-29
            • 2018-01-04
            • 2019-03-09
            • 2019-07-12
            • 1970-01-01
            • 2021-03-14
            相关资源
            最近更新 更多