如何在 Go 中从查询参数中提取逗号分隔的值?

4

我正在使用Gin Web Framework,并尝试找到一种方法将一个逗号分隔的值列表从查询参数绑定到一个结构体中。以下是我的代码片段:

type QueryParams struct {
    Type            []string `form:"type"`
}


func BulkRead(c *gin.Context) {

    params := QueryParams{
        Type:            []string{},
    }

    if err := c.ShouldBindQuery(&params); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": "couldn't bind query params"})
        return
    }
    
    c.Status(200)
}

请求:GET /api/v1/car?type=ford,audi

期望结果:["ford", "audi"]

实际结果:"ford,audi"

有没有简便的方法可以做到这一点?还是我需要编写一个自定义函数来处理它?


我认为你可能需要使用GetQueryArray - Clark McCauley
我尝试了一下,但仍然没有得到我想要的结果,arr,_:= c.GetQueryArray(“type”); fmt.Println(arr [0])->“福特,奥迪” - user16368243
1
该函数无法知道您期望通过逗号分隔的多个值(为什么不是冒号或其他字符?)。也许以下请求将在任何http路由器中自动工作: GET /api/v1/cart?type=ford&type=audi - Fulldump
也许rsql是您API的更合适的解决方案。 - Fulldump
4个回答

阿里云服务器只需要99元/年,新老用户同享,点击查看详情
3

要从查询参数中提取逗号分隔的值,您可以使用 strings 包中的 Split() 方法。我已经为您的情况创建了一个简单的程序如下:

package main

import (
    "fmt"
    "strconv"
    "strings"
)

func main() {

    var cars []string
    qryResult := "ford,audi"
    carBrands := strings.Split(qryResult, ",")
    fmt.Println(carBrands)

    for i := 0; i < len(carBrands); i++ {

        cars = append(cars, strconv.Quote(carBrands[i]))
    }

    fmt.Println(cars)

}

输出:

[ford audi]
["ford" "audi"]

1

可能并没有这样的方法。 通常我会这样做:

type QueryParams struct {
    Type string `form:"type"`
}

func (q *QueryParams) Types() []string {
    return strings.Split(q.Type, ",")
}

func BulkRead(c *gin.Context) {
    params := new(QueryParams)

    if err := c.ShouldBindQuery(&params); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": "couldn't bind query params"})
        return
    }
    c.JSONP(200, map[string]interface{}{
        "types": params.Types(),
    })
}

0

Gin 没有提供这个功能的方法。最简单的解决方案是自己获取查询参数并进行拆分。这只需要两行代码:

func MyHandler(c *gin.Context) {
    ss := strings.Split(c.Query("type"), ",")
    fmt.Println(ss) // [ford audi]

    qp := QueryParams{
        Type: ss,
    }
}

如果您有更改请求方式的选项,请将其更改为: GET /api/v1/car?type=ford&type=audi(重复查询键) 或者对逗号进行URL编码: GET /api/v1/car?type=ford%20audi(, -> %20) 然后context.GetQueryArray将按您的期望工作:
func MyHandler(c *gin.Context) {
    cars, _ := c.GetQueryArray("type")
    fmt.Println(cars) // [ford audi]
}

当然,实现自己的binding.Binding是一个选项,适用于您不仅仅有查询参数的情况,并且想要将绑定逻辑封装到一个地方,但我认为这对于您的用例来说太过于紧张了:
type commaSepQueryBinding struct {}

func (commaSepQueryBinding) Name() string {
    return "comma-sep-query"
}

func (commaSepQueryBinding) Bind(req *http.Request, obj interface{}) error {
    values := req.URL.Query()
    p := obj.(*QueryParams)
    p.Type = strings.Split(values["type"][0], ",")
    return nil
}

func MyHandler(c *gin.Context) {
    q := QueryParams{}
    err := c.ShouldBindWith(&q, &commaSepQueryBinding{})
    if err != nil {
        panic(err)
    }
    fmt.Println(q.Type) // [ford audi]
}

-1

这对你也可能有帮助。

package main

import (
    "log"
    "net/http"
    "strings"

    "github.com/gin-gonic/gin"
)

type TypeBinding struct {
    name string
}

func NewTypeBinding(name string) *TypeBinding {
    return &TypeBinding{
        name: name,
    }
}

func (t *TypeBinding) Name() string {
    return t.name
}

func (t *TypeBinding) Bind(r *http.Request, i interface{}) error {
    ttype := r.URL.Query().Get(t.name)

    ii := i.(*QueryParams)

    ii.Type = strings.Split(ttype, ",")

    return nil
}

type QueryParams struct {
    Type []string `url:"type"`
}

func ggin() {
    router := gin.Default()

    typeBinding := NewTypeBinding("type")
    var opt QueryParams

    router.GET("/", func(c *gin.Context) {
        if err := c.MustBindWith(&opt, typeBinding); err != nil {
            c.JSON(http.StatusBadRequest, gin.H{"error": "couldn't bind query params"})
            return
        }

        log.Printf("type: %v", opt.Type)
        c.String(http.StatusOK, "type: %s", opt.Type)
    })
    router.Run(":8080")
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,