需先用 json.unmarshal 解析外层字符串,再对解出的字符串再次解析;若字段实际为 json 字符串而非对象,应定义为 string 或 json.rawmessage 而非 map[string]interface{}。

JSON 字符串里嵌套了
、"、\,直接 json.Unmarshal 报错怎么办
Go 的 json.Unmarshal 本身不处理“字符串中的转义”,它只解析合法 JSON 文本。如果你拿到的是一个 已经被双引号包裹的 JSON 字符串,而这个字符串内部还含
或 "(比如日志里截出来的字段值),那它其实不是 JSON,而是 JSON 中的一个字符串字段值 —— 此时直接传给 json.Unmarshal 就会报 invalid character '
' in string literal。
常见场景:从 HTTP 响应体、数据库 text 字段、或日志行中提取出一段看似 JSON 的内容,但实际是被多层编码过的字符串。
- 确认原始数据是否真的是 JSON:用在线 JSON 验证器(如 jsonlint.com)粘贴原始字符串,看是否通过
- 如果验证失败,大概率是「JSON 字符串里又套了一层 JSON 字符串」,即类似:
"{"name":"a b","id":123}" - 这种情况要先用
json.Unmarshal解一层,得到字符串值,再对那个字符串值再次json.Unmarshal
<pre class="brush:php;toolbar:false;">raw := "{"name":"a\nb","id":123}"
var s string
if err := json.Unmarshal([]byte(raw), &s); err != nil {
log.Fatal(err) // 这里解出来 s == `{"name":"a
b","id":123}`
}
var data map[string]interface{}
if err := json.Unmarshal([]byte(s), &data); err != nil {
log.Fatal(err)
}
遇到 json: cannot unmarshal string into Go value of type map[string]interface{}
这是最典型的「该解两层却只解了一层」错误。Go 的类型系统很严格:如果字段在 JSON 中是字符串字面量(哪怕内容是合法 JSON),你就不能直接往 map[string]interface{} 里 unmarshal。
- 检查结构体字段类型是否和 JSON 实际类型匹配:比如 API 返回的
"user_info"字段值是字符串"{"age":25}",就不能定义为UserInfo map[string]interface{},而得是UserInfo string - 用
json.RawMessage延迟解析:它能原样保存未解析的 JSON 字节,避免过早类型转换失败
<pre class="brush:php;toolbar:false;">type Resp struct {
UserInfo json.RawMessage `json:"user_info"`
}
// 后续再单独解析:
var user map[string]interface{}
if err := json.Unmarshal(resp.UserInfo, &user); err != nil { ... }
从日志或 HTTP body 中提取 JSON 片段时,换行和空格导致解析失败
很多服务返回的 JSON 是压缩格式(无空格、无换行),但日志系统可能自动加了换行、缩进或前后空格;还有些前端代码用 JSON.stringify
+ 变成空格、%22 没还原。- 不要用
strings.TrimSpace草率清理:它会删掉字符串内部合法的空白(比如 JSON 字符串值里的空格) - 先尝试用
bytes.Trim去掉首尾

