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