url.QueryEscape/Unescape仅用于查询参数的key/value,空格转+;路径段须用PathEscape/Unescape,保留/等合法字符;构建完整URL应使用url.URL结构体配合url.Values.Encode()。

Go 中 url.QueryEscape 和 url.QueryUnescape 是最常用的一对函数
它们专为 URL 查询参数(即 ?key=value 中的 value 部分)设计,不是通用的 URI 编码工具。如果你直接拿它去编码整个 URL 或路径段,会出问题——比如把 / 错误地编码成 %2F,而路径中的斜杠本不该被转义。
常见错误现象:
– 用 url.QueryEscape 编码 https://example.com/a/b?c=1 → 斜杠和冒号全被转义,结果无法访问
– 解码后字符串末尾多出乱码或报 invalid URL escape
- 只用于
key或value单个字段,例如url.QueryEscape("hello world")→hello+world - 空格会被转成
+(符合application/x-www-form-urlencoded规范),不是%20 - 中文、emoji、特殊符号(如
€、?)都能正确处理
路径部分要用 url.PathEscape 和 url.PathUnescape
Go 1.8+ 引入了这两个函数,专门处理 URL 路径段(path segment),比如 /api/v1/users/张三 中的 张三。它保留 /、:、@ 等路径合法字符,只转义真正需要编码的字节。
使用场景:
– 构造 RESTful URL 时拼接动态路径参数
– 解析从请求中提取的路径片段(如 Gin 的 :name 参数)
-
url.PathEscape("张三")→%E5%BC%A0%E4%B8%89,但/不会被动 -
url.PathEscape("a/b")→a%2Fb(只转义/,因为它是路径分隔符) - 注意:它不处理查询参数,别和
QueryEscape混用
完整 URL 构建推荐用 url.URL 结构体 + url.Parse
手动拼接并编码 URL 容易遗漏边界情况。Go 标准库提供了类型安全的方式:
u := &url.URL{
Scheme: "https",
Host: "api.example.com",
Path: "/search",
RawQuery: url.Values{"q": []string{url.QueryEscape("Go 编程")}}.Encode(),
}
fmt.Println(u.String()) // https://api.example.com/search?q=Go+%E7%BC%96%E7%A8%8B
关键点:
– Path 字段应传入已用 url.PathEscape 处理过的路径段
– RawQuery 接收的是已编码的查询字符串(用 url.Values.Encode() 最稳妥)
– 不要自己拼 "?" + query,避免重复编码或漏掉 = & 的转义
-
url.Values{"k": {"a b", "c&d"}}.Encode() →k=a+b&k=c%26d - 如果已有原始查询字符串,用
url.ParseQuery解析后再修改,比正则拆解可靠
解码失败时优先检查输入是否被双重编码
url.QueryUnescape 和 url.PathUnescape 遇到非法转义序列(如 %xy 中 xy 不是十六进制)会返回错误。最常见的原因是前端或中间层重复编码了一次:
立即学习“go语言免费学习笔记(深入)”;
- 原始值:
hello world - 第一次编码:
hello+world - 错误地再编码一次:
hello%2Bworld(+被当成字面量又编码) - 此时用
QueryUnescape解码会失败,因为%2B是加号,但上下文期望的是空格
调试建议:
– 打印原始输入,确认是否含多余 % 或 +
– 用 strings.Count(raw, "%") 初步判断是否过度编码
– 对不可信来源(如 HTTP Header、第三方回调)始终做容错处理,不要假设输入一定合规
