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

huangapple go评论93阅读模式
英文:

How to extract comma separated values from query parameter in Go?

问题

我正在使用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": "无法绑定查询参数"})
        return
    }
    
    c.Status(200)
}

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

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

我得到的结果:"ford,audi"

有没有简单的方法可以实现这个?还是我需要编写一个自定义函数来处理这个?

英文:

I am using the Gin Web Framework and I am trying to find a way to bind a list of comma separated values from a query parameter into a struct. The following is a snippet of my code:

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)
}

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

What I expect: ["ford", "audi"]

What I am getting: "ford,audi"

Is there an easy way to do this? Or will I need to write a custom function to handle this?

答案1

得分: 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"]

这段代码可以从查询参数中提取逗号分隔的值,并将其存储在一个字符串切片中。然后,它使用strconv.Quote()方法将每个值添加到另一个字符串切片中,并打印出结果。

英文:

To extract comma separated values from query parameter you can make use of Split() method from strings package .I have created a simple program for your scenario as follows :

package main

import (
	&quot;fmt&quot;
	&quot;strconv&quot;
	&quot;strings&quot;
)

func main() {

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

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

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

	fmt.Println(cars)

}

Output:

[ford audi]
[&quot;ford&quot; &quot;audi&quot;]

答案2

得分: 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": "无法绑定查询参数"})
		return
	}
	c.JSONP(200, map[string]interface{}{
		"types": params.Types(),
	})
}
英文:

There may not be such a way.
Usually I do this:

type QueryParams struct {
	Type string `form:&quot;type&quot;`
}

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

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

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

</details>



# 答案3
**得分**: 0

Gin没有提供直接的方法来完成这个任务。最简单的解决方案是自己获取查询参数并进行拆分。以下是只需两行代码的示例:

```go
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]
}
英文:

Gin doesn't have a way to do this for you. The easiest solution is to just get the query param and split it yourself. This is literally 2 lines of code:

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

    qp := QueryParams{
        Type: ss,
    }
}

<hr>

If you have the option to change how the request is made, change it to:

GET /api/v1/car?type=ford&amp;type=audi (repeat the query key)

or URL-encode the comma:

GET /api/v1/car?type=ford%20audi (, -> %20)

Then context.GetQueryArray will work as you expect:

func MyHandler(c *gin.Context) {
	cars, _ := c.GetQueryArray(&quot;type&quot;)
	fmt.Println(cars) // [ford audi]
}

<hr>

Of course implementing your own binding.Binding is an option, suited if you have more than just that query parameter and want to encapsulate the binding logic into one place, but I feel it's overkill for your use case:

type commaSepQueryBinding struct {}

func (commaSepQueryBinding) Name() string {
	return &quot;comma-sep-query&quot;
}

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

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

答案4

得分: -1

这是一个Go语言的代码示例,使用了Gin框架来创建一个HTTP服务器。以下是代码的翻译:

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": "无法绑定查询参数"})
			return
		}

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

这段代码创建了一个HTTP服务器,监听在8080端口。当访问根路径"/"时,服务器会尝试将查询参数绑定到QueryParams结构体的Type字段上,并将绑定结果打印出来。如果绑定失败,服务器会返回一个错误响应。

英文:

It might be helpful for you too.

package main

import (
	&quot;log&quot;
	&quot;net/http&quot;
	&quot;strings&quot;

	&quot;github.com/gin-gonic/gin&quot;
)

type TypeBinding struct {
	name string
}

func NewTypeBinding(name string) *TypeBinding {
	return &amp;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, &quot;,&quot;)

	return nil
}

type QueryParams struct {
	Type []string `url:&quot;type&quot;`
}

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

	typeBinding := NewTypeBinding(&quot;type&quot;)
	var opt QueryParams

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

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

huangapple
  • 本文由 发表于 2021年7月6日 08:53:59
  • 转载请务必保留本文链接:https://go.coder-hub.com/68263340.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定