如何在 Go 中正确解码双重编码的 JSON 字符串

13次阅读

如何在 Go 中正确解码双重编码的 JSON 字符串

当 url 编码字符串内部还嵌套了 json 转义(如 `”%22%7b…%7d%22″`),需先 `url.queryunescape`,再用 `json.unmarshal` 两次:第一次解析出原始 json 字符串,第二次解析为结构体

go 开发中,常会遇到从 http 查询参数、表单字段或第三方接口接收到的「双重编码json 字符串——即整个 JSON 文本被 JSON 序列化后,再经 URL 编码(如 ” → %22,{ → %7B, → %5C)。直接对解码后的字符串调用 json.Unmarshal 会失败,因为此时字节切片实际表示的是一个带外层引号的 JSON 字符串字面量(例如 “{“key”:”value”}”),而非可直接映射的 JSON 对象

正确的处理流程是两步解码

  1. URL 解码:使用 url.QueryUnescape 还原百分号编码,得到合法的 JSON 字符串字面量(仍带双引号和转义);
  2. 首次 JSON 解码:将该字符串作为 JSON 值反序列化为 String 类型,自动去除外层引号并还原内部转义,获得纯净的 JSON 字符串;
  3. 二次 JSON 解码:将纯净 JSON 字符串转为 []byte,再解码为目标结构体。

示例代码如下:

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() {     // 原始双重编码字符串(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)     }      // 步骤 2:首次 JSON 解码 → 得到纯净 JSON 字符串     var rawJSON string     if err := json.Unmarshal([]byte(s), &rawJSON); err != nil {         panic(fmt.Sprintf("first unmarshal failed: %v", err))     }      // 步骤 3:二次 JSON 解码 → 映射到结构体     var i Info     if err := json.Unmarshal([]byte(rawJSON), &i); err != nil {         panic(fmt.Sprintf("second unmarshal failed: %v", err))     }      fmt.Printf("%+vn", i)     // 输出:{SessionId:"5331b937-7b55-4c2d-798a-25e574a7e8af" UserId:2 UserName:"datami_op" UserEmail:"datami_op@example.com" UserRoles:[operator]} }

关键注意事项

  • 不要手动字符串替换(如 strings.ReplaceAll(s, “\””, “””)),易出错且无法处理复杂转义;
  • 必须严格按「URL 解码 → JSON 解字符串 → JSON 解结构体」顺序执行,缺一不可;
  • 若原始数据可能为空、非字符串或格式非法,应添加完整错误处理,避免 panic;
  • 此模式也适用于其他嵌套场景,如 Base64 编码的 JSON 字符串,只需将 url.QueryUnescape 替换为 base64.StdEncoding.DecodeString。

通过两阶段反序列化,Go 程序能健壮、安全地处理各类嵌套编码的 JSON 数据,是 API 集成与网关开发中的实用技巧。

text=ZqhQzanResources