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

Go自定义MarshalJSON替换JSON序列化特殊字符失效问题

问题根因

你踩中了Go标准库encoding/json自定义序列化的两个典型坑,结合你描述的“方法内部打印替换成功、最终结果未生效”的现象,根因是以下第二种:

  • 若你给类型实现MarshalJSON时用的是指针接收者,调用json.Marshal时传的是值而非指针,自定义方法根本不会触发。你已经在方法内部加了打印,这个原因可以直接排除。
  • 你要么是在完成字符替换后对结果做了二次json.Marshal调用,要么是构造辅助结构体时没有切断原类型的方法绑定,导致序列化逻辑递归触发;二次序列化时json.Marshal默认开启的HTML转义规则会再次生效,把你替换好的<、>重新转成\u003c、\u003e,等于白做替换。

补充说明:json.Marshal默认会强制转义<、>、&三个HTML特殊字符,这个转义发生在每个字符串值的序列化阶段,手动做字符串替换本质是在转义完成后改结果,只要后续逻辑再触发一次序列化,就会被转义回去,非常不稳定。

正确实现方案

不要手动做字符串替换,手动替换不仅容易遇到二次转义问题,还可能误改JSON结构中非内容部分的字符(比如字段名、其他转义序列里碰巧匹配的片段)。正确做法是从序列化阶段关闭HTML转义,代码如下:

func (t YourStruct) MarshalJSON() ([]byte, error) {
    // 定义和原结构体同字段的类型别名,切断原类型绑定的MarshalJSON方法,避免无限递归
    type Alias YourStruct
    a := Alias(t)

    var buf bytes.Buffer
    enc := json.NewEncoder(&buf)
    // 核心配置:关闭HTML特殊字符转义
    enc.SetEscapeHTML(false)
    if err := enc.Encode(&a); err != nil {
        return nil, err
    }
    // 去掉Encoder默认追加的末尾换行,保证返回合法JSON
    res := bytes.TrimRight(buf.Bytes(), "\n")
    return res, nil
}

这个方案的优势:

  • 不需要做任何事后字符串替换,序列化阶段就不会主动转义<、>,从根源避免替换后被还原的问题
  • 类型别名的写法完全保留原结构体的字段、tag配置,不需要重复维护字段列表
  • 不会破坏原有JSON结构,和默认序列化逻辑除了不转义HTML字符外完全一致
验证

实现上述方法后,直接调用json.Marshal序列化你的结构体,返回结果里的<、>会原样保留,不会再被转义为unicode编码形式。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 04:54:12