golang将结构体编码为URL查询参数插件库qs的使用

Golang将结构体编码为URL查询参数插件库qs的使用

安装

go get github.com/sonh/qs

基本使用

qs是一个零依赖的包,用于将结构体编码为url.Values。

import (
    "github.com/sonh/qs"
)

包qs导出了NewEncoder()函数来创建编码器。编码器会缓存结构体信息以加速编码过程,强烈建议使用单个实例。

使用WithTagAlias()函数可以注册自定义标签别名(默认为qs):

encoder = qs.NewEncoder(
    qs.WithTagAlias("myTag"),
)

编码器有Values()Encode()函数将结构体编码为url.Values

支持的数据类型

  • 所有基本类型(bool, uint, string, float64,…)
  • struct
  • slice, array
  • pointer
  • time.Time
  • 自定义类型

示例

type Query struct {
    Tags   []string  `qs:"tags"`
    Limit  int       `qs:"limit"`
    From   time.Time `qs:"from"`
    Active bool      `qs:"active,omitempty"`  // 省略空值
    Ignore float64   `qs:"-"`                 // 忽略该字段
}

query := &Query{
    Tags:   []string{"docker", "golang", "reactjs"},
    Limit:  24,
    From:   time.Unix(1580601600, 0).UTC(),
    Ignore: 0,
}

encoder := qs.NewEncoder()
values, err := encoder.Values(query)
if err != nil {
    // 处理错误
}
fmt.Println(values.Encode()) // (未转义) 输出: "from=2020-02-02T00:00:00Z&limit=24&tags=docker&tags=golang&tags=reactjs"

布尔值格式

使用int选项将布尔值编码为整数:

type Query struct {
    DefaultFmt bool `qs:"default_fmt"`
    IntFmt     bool `qs:"int_fmt,int"`
}

query := &Query{
    DefaultFmt: true, 
    IntFmt:     true,
}
values, _ := encoder.Values(query)
fmt.Println(values.Encode()) // (未转义) 输出: "default_fmt=true&int_fmt=1"

时间格式

默认情况下,包将time.Time值编码为RFC3339格式。

包含"second""millis"选项表示该字段应编码为秒或毫秒:

type Query struct {
    Default time.Time   `qs:"default_fmt"`
    Second  time.Time   `qs:"second_fmt,second"` // 使用`second`选项
    Millis  time.Time   `qs:"millis_fmt,millis"` // 使用`millis`选项
}

t := time.Unix(1580601600, 0).UTC()
query := &Query{
    Default: t,
    Second:  t,
    Millis:  t,
}

encoder := qs.NewEncoder()
values, _ := encoder.Values(query)
fmt.Println(values.Encode()) // (未转义) 输出: "default_fmt=2020-02-02T00:00:00Z&millis_fmt=1580601600000&second_fmt=1580601600"

切片/数组格式

默认情况下,切片和数组编码为具有相同值名称的多个URL值。

type Query struct {
    Tags []string `qs:"tags"`
}

values, _ := encoder.Values(&Query{Tags: []string{"foo","bar"}})
fmt.Println(values.Encode()) // (未转义) 输出: "tags=foo&tags=bar"

包含comma选项表示该字段应编码为单个逗号分隔的值:

type Query struct {
    Tags []string `qs:"tags,comma"`
}

values, _ := encoder.Values(&Query{Tags: []string{"foo","bar"}})
fmt.Println(values.Encode()) // (未转义) 输出: "tags=foo,bar"

包含bracket选项表示多个URL值应在值名称后附加"[]":

type Query struct {
    Tags []string `qs:"tags,bracket"`
}

values, _ := encoder.Values(&Query{Tags: []string{"foo","bar"}})
fmt.Println(values.Encode()) // (未转义) 输出: "tags[]=foo&tags[]=bar"

index选项将在值名称后附加带括号的索引号:

type Query struct {
    Tags []string `qs:"tags,index"`
}

values, _ := encoder.Values(&Query{Tags: []string{"foo","bar"}})
fmt.Println(values.Encode()) // (未转义) 输出: "tags[0]=foo&tags[1]=bar"

嵌套结构体

所有嵌套结构体都使用带括号的父值名称进行范围编码:

type User struct {
    Verified bool      `qs:"verified"`
    From     time.Time `qs:"from,millis"`
}

type Query struct {
    User User `qs:"user"`
}

query := Query{
    User: User{
        Verified: true,
        From: time.Now(),
    },
}
values, _ := encoder.Values(query)
fmt.Println(values.Encode()) // (未转义) 输出: "user[from]=1601623397728&user[verified]=true"

自定义类型

实现以下函数:

  • EncodeParam 将自身编码为查询参数
  • IsZero 检查对象是否为零以确定编码时是否应省略
type NullableName struct {
	First string
	Last  string
}

func (n NullableName) EncodeParam() (string, error) {
	return n.First + n.Last, nil
}

func (n NullableName) IsZero() bool {
	return n.First == "" && n.Last == ""
}

type Struct struct {
    User  NullableName `qs:"user"`
    Admin NullableName `qs:"admin,omitempty"`
}

s := Struct{
    User: NullableName{
        First: "son",
        Last:  "huynh",
    },
}
encoder := qs.NewEncoder()

values, err := encoder.Values(&s)
if err != nil {
    // 处理错误
    fmt.Println("failed")
    return
}
fmt.Println(values.Encode()) // (未转义) 输出: "user=sonhuynh"

限制

  • 如果slice/array中的元素是struct数据类型,则多级嵌套有限制
  • 目前还没有解码器

将在未来版本中改进

许可证

根据MIT许可证分发,更多详情请参阅代码中的许可证文件。


更多关于golang将结构体编码为URL查询参数插件库qs的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang将结构体编码为URL查询参数插件库qs的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


Golang 结构体编码为 URL 查询参数 - qs 库使用指南

qs 是一个流行的 Go 库,用于将结构体编码为 URL 查询参数。它提供了比标准库更强大的功能,支持嵌套结构体、数组、切片等复杂类型的编码。

安装 qs 库

go get github.com/google/go-querystring/query

基本使用示例

package main

import (
	"fmt"
	"github.com/google/go-querystring/query"
)

type Options struct {
	Query   string `url:"q"`
	ShowAll bool   `url:"all"`
	Page    int    `url:"page"`
}

func main() {
	opt := Options{
		Query:   "golang",
		ShowAll: true,
		Page:    2,
	}

	v, err := query.Values(opt)
	if err != nil {
		panic(err)
	}

	fmt.Println(v.Encode()) // 输出: q=golang&all=true&page=2
}

高级功能

1. 嵌套结构体

type Filter struct {
	Category string `url:"category"`
	PriceMin int    `url:"price_min"`
}

type SearchOptions struct {
	Query  string `url:"q"`
	Filter Filter `url:"filter"`
}

func main() {
	opt := SearchOptions{
		Query: "laptop",
		Filter: Filter{
			Category: "electronics",
			PriceMin: 500,
		},
	}

	v, _ := query.Values(opt)
	fmt.Println(v.Encode()) 
	// 输出: q=laptop&filter.category=electronics&filter.price_min=500
}

2. 数组和切片

type Params struct {
	IDs    []int  `url:"id"`
	Colors []string `url:"color"`
}

func main() {
	p := Params{
		IDs:    []int{1, 2, 3},
		Colors: []string{"red", "green", "blue"},
	}

	v, _ := query.Values(p)
	fmt.Println(v.Encode())
	// 输出: id=1&id=2&id=3&color=red&color=green&color=blue
}

3. 自定义编码器

type CustomTime struct {
	time.Time
}

func (t CustomTime) EncodeValues(key string, v *url.Values) error {
	v.Add(key, t.Format("2006-01-02"))
	return nil
}

type EventParams struct {
	Name string     `url:"name"`
	Date CustomTime `url:"date"`
}

func main() {
	now := time.Now()
	p := EventParams{
		Name: "Conference",
		Date: CustomTime{now},
	}

	v, _ := query.Values(p)
	fmt.Println(v.Encode())
	// 输出类似: name=Conference&date=2023-11-15
}

4. 忽略空值

type Options struct {
	Query string `url:"q,omitempty"`
	Limit int    `url:"limit,omitempty"`
}

func main() {
	opt := Options{
		Query: "",
		Limit: 0,
	}

	v, _ := query.Values(opt)
	fmt.Println(v.Encode()) // 输出空字符串,因为所有字段都是空值
}

5. 自定义分隔符

默认情况下,嵌套结构体使用点号(.)作为分隔符,但可以自定义:

type Nested struct {
	Field string `url:"field"`
}

type Params struct {
	Nested Nested `url:"nested,comma"`
}

func main() {
	p := Params{
		Nested: Nested{Field: "value"},
	}

	v, _ := query.Values(p)
	fmt.Println(v.Encode()) // 输出: nested[field]=value
}

注意事项

  1. qs 库不支持解码 URL 查询参数回结构体,只支持编码
  2. 对于复杂嵌套结构,确保字段标签正确设置
  3. 默认情况下,零值会被编码,可以使用 omitempty 标签忽略它们
  4. 对于自定义类型,可以实现 Encoder 接口来自定义编码行为

qs 库是构建 REST API 客户端或处理复杂查询参数的理想选择,它比标准库的 url.Values 提供了更丰富的功能。

回到顶部