结构体字段未加 query tag 时默认被跳过;go-querystring 等库依赖该 tag 控制导出逻辑,手动用 url.Values 更可控且避坑。

结构体字段没加 query tag 时默认不参与序列化
Go 标准库没有原生支持结构体转 URL 查询参数(application/x-www-form-urlencoded),得靠第三方库(比如 google/go-querystring)或手动拼接。这些库统一依赖结构体字段的 query tag 来决定是否导出、用什么键名、是否忽略空值。
不加 query tag 的字段默认被跳过,哪怕它有值;加了但值为空(如空字符串、零值整数、nil 切片)时,是否保留取决于 tag 里的选项。
常见写法示例:
type User struct {
Name string `query:"name"`
ID int `query:"id"`
Email string `query:"email,omitempty"`
Token string `query:"-"` // 完全忽略
}
-
omitempty:该字段为空值时不加入 URL 参数(注意:对字符串是空串,对 int 是 0,对指针是 nil) -
-:强制忽略,无论有没有值 - 没写 tag 也等价于
-,不是“自动用字段名”
用 url.Values 手动拼接比依赖反射更可控
很多项目初期直接上 go-querystring,但遇到嵌套结构体、切片扁平化、重复 key(如 ids=1&ids=2)、或需要预处理值(如时间格式化)时,反射方案容易失控。此时用标准库 url.Values 显式赋值反而更稳。
立即学习“go语言免费学习笔记(深入)”;
例如要支持 tags[]=a&tags[]=b 或 tags=a,b 这类变体,必须自己控制编码逻辑:
v := url.Values{}
v.Set("name", u.Name)
v.Add("tags", "a") // Add 允许重复 key
v.Add("tags", "b")
// 或 v.Set("tags", strings.Join(u.Tags, ","))
-
v.Set()覆盖已有同名 key,v.Add()追加,生成多个相同 key - 对 slice 类型,不能直接
v.Add("items", items)—— 必须遍历调用Add或自行 join - 中文、特殊字符必须用
url.QueryEscape处理,url.Values.Encode()内部已做,但手动拼 key=value 时别漏掉
go-querystring 对嵌套结构体和指针字段行为不直观
这个库对嵌套结构体默认展开为 user.name 形式,且不支持自定义分隔符(比如想变成 user_name 就得自己预处理)。更麻烦的是,它把 *string 和 string 当作等价类型,但 nil 指针在 omitempty 下会被跳过——而你可能期望它输出空字符串。
典型陷阱:
type Req struct {
Filter *Filter `query:"filter"`
}
type Filter struct {
Status string `query:"status"`
}
// 如果 Filter == nil,整个 filter.status 都不会出现,哪怕你想传 status=""
- 嵌套结构体字段名拼接用点号(
.),不可配置 - 指针字段为 nil 时,即使子字段有
omitempty=false也无效 - 不支持 map 类型字段(会 panic),需提前转成 struct 或手动处理
URL 参数长度限制和服务器兼容性比序列化逻辑更关键
再正确的 query tag 也救不了超长 URL。GET 请求受浏览器、代理、Web 服务器(如 Nginx 默认 4k、Apache 8k)共同限制。如果参数多或值大(比如 base64 图片、长 JSON 字符串),应改用 POST + application/x-www-form-urlencoded body,而非硬塞进 URL。
另外注意:
- 某些后端框架(如 Django、Rails)默认只解析
key=value形式,不支持key[]=val1&key[]=val2的数组语法,除非显式开启 - Go 的
url.ParseQuery能解析重复 key,但返回的是map[string][]string,取值时别直接用m["k"][0]而不检查切片长度 - 前端 JS 的
URLSearchParams与 Go 的url.Values编码规则一致,但对空格编码不同(JS 用+,Go 用%20),跨端调试时留意
真正卡住人的往往不是 tag 怎么写,而是没想清楚这个参数到底该不该放 URL 里。


















