17370845950

如何正确解码 URL 编码的 JSON 字符串并解析为 Go 结构体

当 json 数据被双重编码(先 json 序列化,再 url 编码),需先 `url.queryunescape` 解码,再用 `json.unmarshal` 解析;若字符串本身是 json 编码的字符串(即外层带引号、内部转义),需额外一次 `json.unmarshal` 去除外层引号并还原原始 json。

在 Go 中处理从 URL 查询参数、表单或 API 响应中获取的 JSON 数据时,常遇到一种典型场景:原始 JSON 字符串被先序列化为 JSON 字符串(自动添加外层双引号并转义内部引号),再经过 url.QueryEscape 编码(如 %22%7B...%7D%22)。此时直接对 url.QueryUnescape 后的结果调用 json.Unmarshal 会失败,因为解码后得到的是一个带引号的 JSON 字符串字面量(例如 "\"{\\\"key\\\":\\\"value\\\"}\""),而非可直接解析的 JSON 对象。

正确的处理流程分两步:

  1. URL 解码:使用 url.QueryUnescape 还原原始字节;
  2. JSON 字符串解引用:将解码结果再次作为 JSON 字符串反序列化,以剥离外层引号、还原转义,得到真正的 JSON 字节流;
  3. 最终结构体解析:用该 JSON 字节流解析为目标 Go 结构体。

以下是一个完整示例:

package main

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

type Info struct {
    SessionId string   `json:"sessionId"`
    UserId    int      `json:"userId"`
    UserName  string   `json:"userName"`
    UserEmail string   `json:"userEmail"`
    UserRoles []string `json:"userRoles"`
}

func main() {
    // 模拟双重编码的字符串:%22%7B...%7D%22 → 即 URL 编码后的 JSON 字符串
    encoded := "%22%7B%5C%22sessionId%5C%22%3A%5C%225331b937-7b55-4c2d-798a-25e574a7e8af%5C%22%2C%5C%22userId%5C%22%3A2%2C%5C%22userName%5C%22%3A%5C%22datami_op%5C%22%2C%5C%22userEmail%5C%22%3A%5C%22datami_op%40example.com%5C%22%2C%5C%22userRoles%5C%22%3A[%5C%22operator%5C%22]%7D%22"

    // 步骤 1:URL 解码
    s, err := url.QueryUnescape(encoded)
    if err != nil {
        panic(err)
    }
    fmt.Printf("URL decoded: %s\n", s) // 输出:"{\"sessionId\":\"...\",\"userRoles\":[\"operator\"]}"

    // 步骤 2:将解码后的字符串视为 JSON 字符串,再次 Unmarshal → 得到原始 JSON 字节
    var unquoted string
    if err := json.Unmarshal([]byte(s), &unquoted); err != nil {
        panic(err)
    }
    fmt.Printf("Unquoted JSON: %s\n", unquoted) // 输出:{"sessionId":"...", "userRoles":["operator"]}

    // 步骤 3:解析为结构体
    var info Info
    if e

rr := json.Unmarshal([]byte(unquoted), &info); err != nil { panic(err) } fmt.Printf("Parsed struct: %+v\n", info) }

关键点总结

  • 不要手动字符串替换(如 strings.ReplaceAll(s, "\\\"", "\"")),易出错且不健壮;
  • json.Unmarshal 可安全处理已转义的 JSON 字符串字面量(含 \"、\n 等),是标准且可靠的方式;
  • 若不确定是否双重编码,可先打印 url.QueryUnescape 后的字符串——若开头结尾是 " 且内部大量 \",即需二次 json.Unmarshal;
  • 生产环境建议始终检查 err,避免静默失败。

通过这一模式,你就能稳健地解析来自 Web 表单、重定向参数或遗留接口中那些“套娃式”编码的 JSON 数据。