应使用 url.ParseQuery 解析 query 参数,它自动解码、处理重复 key;HTTP handler 中需先调用 r.ParseForm() 再通过 r.URL.Query() 安全访问,避免手动解析 RawQuery 导致编码错误或 key 覆盖。

query参数解析要用 url.ParseQuery,不是 url.Parse
很多人直接对完整 URL 调用 url.Parse,拿到 *url.URL 后只读 RawQuery 字段,却忘了它只是字符串,没解码也没结构化。真正要提取键值对,必须用 url.ParseQuery —— 它会自动做 URL 解码、处理重复 key、合并相同键的多个值。
-
url.ParseQuery("a=1&b=2&b=3")返回map[string][]string{"a": ["1"], "b": ["2", "3"]} - 若用
url.Parse+ 手动分割RawQuery,会漏掉空格变空格、%20未解码、重复 key 被覆盖等问题 - 注意:该函数返回的是
map[string][]string,不是map[string]string;即使参数只出现一次,值也是长度为 1 的切片
从 http.Request 中安全取 query 参数
在 HTTP handler 里,别直接操作 r.URL.RawQuery 或拼接字符串解析。标准做法是先调用 r.ParseForm()(它内部已调用 ParseQuery),再通过 r.Form 或 r.URL.Query() 访问。
-
r.URL.Query()只解析 URL 查询参数(?key=val),不包含 POST 表单数据 -
r.FormValue("key")会合并 URL 查询参数和 POST 表单(按规范优先级:POST > URL),但只返回第一个值([]string中的[0]) - 若需所有值或区分来源,用
r.URL.Query().Get("key")(取第一个)或r.URL.Query()["key"](取全部) - 务必检查错误:
err := r.ParseForm(); if err != nil { /* 处理解析失败,如 malformed query */ }
url.Values 是可修改的 map,但写法要注意
url.Values 是 map[string][]string 的别名,支持增删改,但常见误操作是直接赋值 v["k"] = []string{"v"} 而忘记初始化 map —— 这会导致 panic。
- 正确初始化:
values := url.Values{} // 或 make(url.Values) - 添加参数:
values.Set("page", "1")(覆盖)、values.Add("sort", "asc")(追加)、values.Del("q")(删除) - 生成查询字符串:
values.Encode()—— 它会自动编码键和值,比如空格变%20,中文变 UTF-8 编码 - 不要手动拼接
?a=1&b=2,避免未编码字符导致 400 错误
中文、特殊字符和空值的典型陷阱
URL 查询参数中含中文、+、/、? 等字符时,不经过 Encode() 或 ParseQuery() 会出错;而空字符串、全空白字符串、缺失 key 的情况也容易被忽略。
立即学习“go语言免费学习笔记(深入)”;
-
前端传
?name=张三&tag=,r.URL.Query().Get("tag")返回空字符串"",不是nil;判断是否存在要用_, ok := r.URL.Query()["tag"] -
url.ParseQuery("q=hello+world")中的+会被当成空格解码,结果是"hello world";若真要字面量+,前端需编码为%2B - 路径中带查询参数时(如
/api?x=1),注意r.URL.Path不含?后内容,r.URL.RawQuery才是原始 query 字符串
实际开发中最容易卡住的,是把 url.Values 当普通 map 直接赋值,或者混淆 FormValue 和 Query().Get 的行为差异——前者混合了 POST 数据,后者只看 URL。










