
当 API 返回的 JSON 中某个字段值是被双引号包裹的 JSON 数组字符串(即“JSON-in-JSON”),需先将其类型断言为 string,再用 json.Unmarshal 二次解析,才能正确转为 Go 的 []map[string]interface{} 或 []map[string]string。
当 api 返回的 json 中某个字段值是被双引号包裹的 json 数组字符串(即“json-in-json”),需先将其类型断言为 string,再用 `json.unmarshal` 二次解析,才能正确转为 go 的 `[]map[string]interface{}` 或 `[]map[string]string`。
在 Go 中处理 JSON 数据时,标准库 encoding/json 默认按 JSON 结构严格解析:若某字段值在原始 JSON 中被写成带引号的字符串(如 "content":"[{\"id\":\"123\"}]"),Go 会将其视为 string 类型,而非自动递归解析其内部结构。直接类型断言为 []interface{} 会导致 panic —— 正如错误提示 interface conversion: interface is string, not []interface{} 所示。
正确做法是两步解析:
- 先将顶层 JSON 解析为 map[string]interface{},获取 "content" 字段并断言为 string;
- 再将该字符串作为新的 JSON 输入,调用 json.Unmarshal 二次解析为目标结构。
以下是推荐的完整实现方式:
package main
import (
"fmt"
"encoding/json"
)
func check(e error) {
if e != nil {
panic(e)
}
}
var incomingJson = `{
"status":"success",
"content":"[{\"id\":\"567670128\"},{\"id\":\"567670129\"}]"
}`
func main() {
// 第一步:解析外层 JSON
var data map[string]interface{}
err := json.Unmarshal([]byte(incomingJson), &data)
check(err)
// 第二步:提取 content 字段,并断言为 string
contentStr, ok := data["content"].(string)
if !ok {
panic("content field is not a string")
}
// 第三步:将 content 字符串作为 JSON 二次解析
var contentArray []map[string]string
err = json.Unmarshal([]byte(contentStr), &contentArray)
check(err)
// 现在可安全访问
for i, item := range contentArray {
fmt.Printf("Item %d: %+v\n", i, item)
// 输出:Item 0: map[id:567670128]
// Item 1: map[id:567670129]
}
}
✅ 关键要点:
- 始终检查类型断言是否成功(如 contentStr, ok := data["content"].(string)),避免运行时 panic;
- 若字段内容结构固定,优先使用强类型切片(如 []map[string]string)而非 []interface{},提升类型安全与可读性;
- 对于更复杂的嵌套结构,可定义结构体(如 type ContentItem struct { ID stringjson:"id"})并解析为 []ContentItem,进一步增强健壮性;
- 不要尝试用 strings.Replace 或正则“手动解包”,既不安全也不符合 JSON 规范(如字符串中含转义引号、Unicode 等会出错)。
这种双重解析模式常见于遗留 API 或跨语言兼容场景,本质是应对非标准 JSON 序列化行为——理解并正确处理它,是构建健壮 Go 客户端的关键一环。











