You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何url.ParseQuery方法返回结果不符合预期?如何修正?

URL查询参数解析结果不符的问题分析与解决

问题描述

给定的Go程序执行后输出结果为:
{"x":["1 1 3"], "y":["2", "3"]}
但预期结果应为:
{"x":["1+1+3"], "y":["2", "3"]}

原因

net/url包的ParseQuery函数遵循application/x-www-form-urlencoded编码规范,该规范中+符号会被解析为空格。所以当解析x=1+1+3时,字符串里的+会被自动替换成空格,导致最终x字段的值变成了1 1 3。

修改方案

方案一:解析后替换空格为+

在解析完成后,遍历url.Values中的所有值,将空格替换回+即可:

import (
    "encoding/json"
    "fmt"
    "log"
    "net/url"
    "strings"
)

func main() {
    m, err := url.ParseQuery(`x=1+1+3&y=2&y=3`)
    if err != nil {
        log.Fatal(err)
    }
    // 遍历替换每个值里的空格为+
    for key, values := range m {
        updatedValues := make([]string, len(values))
        for idx, val := range values {
            updatedValues[idx] = strings.ReplaceAll(val, " ", "+")
        }
        m[key] = updatedValues
    }
    fmt.Println(toJSON(m))
}

func toJSON(m any) string {
    js, err := json.Marshal(m)
    if err != nil {
        log.Fatal(err)
    }
    return strings.ReplaceAll(string(js), ",", ", ")
}

方案二:手动拆分并解码键值对

如果想避免ParseQuery自动替换+,可以手动拆分查询字符串,对每个值单独使用QueryUnescape处理(该函数不会将+替换为空格,只会解码%xx格式的转义字符):

import (
    "encoding/json"
    "fmt"
    "log"
    "net/url"
    "strings"
)

func main() {
    queryStr := `x=1+1+3&y=2&y=3`
    m := url.Values{}
    // 按&拆分每个键值对
    for _, pair := range strings.Split(queryStr, "&") {
        kv := strings.SplitN(pair, "=", 2)
        if len(kv) != 2 {
            continue
        }
        key := kv[0]
        // 仅解码%xx转义,保留+
        value, err := url.QueryUnescape(kv[1])
        if err != nil {
            log.Fatal(err)
        }
        m.Add(key, value)
    }
    fmt.Println(toJSON(m))
}

func toJSON(m any) string {
    js, err := json.Marshal(m)
    if err != nil {
        log.Fatal(err)
    }
    return strings.ReplaceAll(string(js), ",", ", ")
}

内容的提问来源于stack exchange,提问作者Denis

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 11:05:16