当前位置:首页 > 文章列表 > Golang > Go问答 > Go json.Encoder.SetEscapeHTML(false) 什么时候适合关闭转义

Go json.Encoder.SetEscapeHTML(false) 什么时候适合关闭转义

来源:17golang原创 2026-11-05 10:01:58 0浏览 收藏

当 JSON 作为独立数据交给 JSON 解析器消费,而且你希望输出中的 URL、文本片段保留可读的 &、、> 时,可以对当前 Encoder 调用 SetEscapeHTML(false)。如果只是担心默认转义会改变 URL 的含义,通常不必关闭:正常 JSON 解析会还原相同的字符串值。

官方地址:https://pkg.go.dev/encoding/json

把转义设置当成输出契约

这个开关适合放在“输出契约”中理解。业务值是 URL 或文本,JSON 则是它们的一种序列化表示。默认把某些字符写成 Unicode 转义,不意味着业务值被改写。把编码后的字节直接展示给人看,与把 JSON 解析后交给业务处理,是不同的使用方式。

例如 URL 参数之间的连接符,在默认 JSON 字节中可以表示为 \u0026,解析后仍然是 &。关闭 HTML 转义主要改变这类字符的表示方式,而不是修复一个解析错误。若消费方把整段 JSON 文字当成 URL 使用,应该纠正消费方式,而不是要求序列化器迁就错误的数据层次。

哪些场景需要保留可读字符

一个明确的场景是独立 JSON 导出文件:维护者会直接阅读、比较其中的链接和描述,频繁出现的转义让人工查看不便。另一个场景是协议明确要求某种字符表示,此时设置应放在拥有该输出协议的函数中,保持同一出口的字节风格一致。

不要因为某处不喜欢转义,就顺手改掉所有 JSON 出口。调用只影响这一 Encoder 实例及其后续编码,不会修改 json.Marshal 的默认设置,也不是进程级全局开关。创建新 Encoder 时,仍需要按该出口的要求显式配置。

消费方式判断重点
独立 JSON 文件,常由人直接阅读保留原字符是否更便于维护
标准 JSON 解析器读取字段解析值一致,通常无须为 URL 关闭
要求固定字节的外部协议遵循协议明确约定
输出还会被嵌入 HTML不能沿用独立 JSON 的决策;本文不展开模板处理
业务字符串JSON表示和消费契约的静态关系图
输出契约说明图:业务字符串与 JSON 字节表示分属不同层;独立数据出口和消费要求共同决定编码设置。

用同一个输入比较两种编码

下面用一个带查询参数的示例地址和一段标记文本比较输出。example.invalid 是示例用途,不涉及实际网络请求。代码保存为 main.go 后可在自己的 Go 环境运行;这里提供的是语义示例,不声称已执行。

package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "os"
)

type Payload struct {
    Link string `json:"link"`
    Text string `json:"text"`
}

// encode 仅配置当前编码器,保留 Encode 的末尾换行。
func encode(v Payload, escapeHTML bool) ([]byte, error) {
    var buf bytes.Buffer
    enc := json.NewEncoder(&buf)
    enc.SetEscapeHTML(escapeHTML)
    if err := enc.Encode(v); err != nil {
        return nil, fmt.Errorf("编码 JSON: %w", err)
    }
    return buf.Bytes(), nil
}

func run() error {
    input := Payload{
        Link: "https://example.invalid/search?a=1&b=2",
        Text: "中文",
    }
    escaped, err := encode(input, true)
    if err != nil { return err }
    readable, err := encode(input, false)
    if err != nil { return err }

    // 分别解析,比较字符串值;不对编码后的字节做替换。
    var left, right Payload
    if err := json.Unmarshal(escaped, &left); err != nil {
        return fmt.Errorf("解析默认编码: %w", err)
    }
    if err := json.Unmarshal(readable, &right); err != nil {
        return fmt.Errorf("解析关闭转义的编码: %w", err)
    }
    fmt.Printf("默认编码:%s", escaped)
    fmt.Printf("关闭转义:%s", readable)
    fmt.Printf("字节相同:%v\n", bytes.Equal(escaped, readable))
    fmt.Printf("值均还原:%v\n", left == input && right == input)
    return nil
}

func main() {
    if err := run(); err != nil {
        fmt.Fprintln(os.Stderr, err)
        os.Exit(1)
    }
}

按标准编码语义,默认编码会对示例中的连接符和尖括号使用相应转义,关闭后保留这些字符。两份字节会有差异,而分别 Unmarshal 得到的 Link 与 Text 都应与 input 一致。后两项比较特意分开:字节不相等和业务值相等可以同时成立。

encode 接受布尔参数,使选择集中在序列化出口;调用方不用在结果上找字符串替换。代码也保留 Encode 的尾部换行。这个换行是 Encoder 的输出行为,与 HTML 转义开关是两个独立问题,关闭开关不会让 Encode 变成 Marshal 的逐字节替代品。

关闭 HTML 转义不会关闭 JSON 转义

名称中的 HTML 不能省略。SetEscapeHTML(false) 不会把字符串变成原样粘贴的裸文本。JSON 必须处理的双引号、反斜杠和控制字符仍然按 JSON 规则编码;中文原本通常就不需要因此改写。若诉求是“所有字符都不转义”,这个开关并不提供这样的模式。

当前 encoding/json 的字符串编码实现还对 U+2028 和 U+2029 保留转义处理。因此不能承诺“传 false 后不存在任何 Unicode 转义”。定位问题时,先确认看到的具体字符和实际字节,再判断它是否属于该开关控制的集合。

另一个反例是二次编码。若业务已经持有一段完整 JSON 文本,却把它作为普通 Go string 再 Encode,得到的是包含该文本的 JSON 字符串,内部引号自然需要转义。这与 HTML 字符转义无关。关闭开关不会把“JSON 字符串值”自动变回原先的对象。

HTML字符转义开关与JSON必要转义的边界结构图
编码边界说明图:Encoder 设置控制特定 HTML 字符的表示,JSON 必要转义及尾部换行有各自规则,不应混为同一个开关。

字节不同会影响哪些下游处理

如果下游处理的是解析值,选择通常只影响可读性。如果处理的是编码后的原始字节,例如文件快照、摘要或协议中的签名输入,则表示差异就有实际影响。应在约定序列化方式后再计算,而不是计算后继续修改输出。

从 Marshal 改到 Encoder 时,还要把末尾换行和缩进一并纳入字节约定。这个开关本身也不等于规范化 JSON,更不能仅靠它保证不同语言的编码器输出完全相同。本文只处理普通字段的字符表示,不延伸自定义 MarshalJSON 的所有行为。

不要对整个结果全局替换转义序列。原始字符串里可能本来就包含反斜杠与字母组成的文字,盲替换容易把值改变。应在编码时选好参数;若已有 JSON,需要更改表示,也应先明确数据结构与重新编码要求。

决定开关前的几个具体问题

为什么客户端仍显示反斜杠?

先区分查看的是原始响应字节,还是已经解析后的字段。有些调试工具还会为展示再加一层转义。也要排除将已有 JSON 文本作为普通字符串再次编码的情况。

SetEscapeHTML(false) 会同时关闭缩进吗?

不会。缩进由 SetIndent 控制,末尾换行属于 Encode 的输出行为。想改变其中一项,就使用对应接口,别把它们绑成一个设置。

什么时候保留默认设置就足够?

消费方按 JSON 解析且没有特殊字节要求时,默认转义通常不妨碍业务值。只有明确需要改善独立 JSON 的可读性或满足输出契约时,再局部配置该 Encoder。

资料:SetEscapeHTML 文档、Encoder 实现、字符串编码实现。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
Go io.ReadFull 怎样处理固定长度协议的半包和 EOFGo io.ReadFull 怎样处理固定长度协议的半包和 EOF
上一篇
Go io.ReadFull 怎样处理固定长度协议的半包和 EOF
Go io.MultiReader 拼接多个文件时怎么判断中间文件已经读完
下一篇
Go io.MultiReader 拼接多个文件时怎么判断中间文件已经读完
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • PubMedQA数据集详解:生物医学问答基准、功能与应用指南
    PubMedQA
    深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
    891次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    891次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    976次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    961次使用
  • MMBench详解:多模态大模型基准测试、功能特点与使用指南
    MMBench
    MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
    788次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议 和 隐私政策
返回登录
  • 重置密码