news 2026/9/10 22:59:31

Gin 如何用 PureJSON 输出字面量 HTML 特殊字符而不是 JSON 默认转义

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Gin 如何用 PureJSON 输出字面量 HTML 特殊字符而不是 JSON 默认转义

Gin 如何用 PureJSON 输出字面量 HTML 特殊字符而不是 JSON 默认转义

【免费下载链接】ginGin is a high-performance HTTP web framework written in Go. It provides a Martini-like API but with significantly better performance—up to 40 times faster—thanks to httprouter. Gin is designed for building REST APIs, web applications, and microservices.项目地址: https://gitcode.com/GitHub_Trending/gi/gin

当你用 Gin 的c.JSON返回包含<>&的字符串时,响应体里看到的全是\u003c\u003e\u0026这类 Unicode 转义,前端拿到后需要再还原一次。如果你的接口直接面向 JSON 消费者(而不是把 JSON 嵌进 HTML 里),这些转义只会干扰可读性。Gin 提供c.PureJSON来解决这个问题:它在序列化前关闭 HTML 转义,让特殊字符以字面量形式输出。本文基于本仓库的 docs/doc.md 中 PureJSON 章节、渲染器实现与测试断言,给出一条可运行、可核对的最小操作路径。当前仓库 go.mod 声明go 1.25.0,文档中提到的 Go 1.6 限制(见下文)对当前版本自然满足。

为什么c.JSON会把 HTML 特殊字符转义

先明确默认行为是什么。Gin 的 JSON 编码器接口对SetEscapeHTML的注释写得很清楚(codec/json/api.go):

默认行为是把&<>转义为\u0026\u003c\u003e,以避免把 JSON 嵌入 HTML 时可能引发的安全问题;在转义影响可读性的非 HTML 场景下,调用SetEscapeHTML(false)关闭这一行为。

c.JSON走的是Marshal路径,保留默认转义。仓库测试 context_test.go 里的TestContextRenderJSON就是这条默认行为的断言:输入H{"foo": "bar", "html": "<b>"},期望响应体为{"foo":"bar","html":"\u003cb\u003e"}Content-Typeapplication/json; charset=utf-8。这就是你遇到"字面量变转义"现象的直接来源。

PureJSON 的实现路径

c.PureJSON在 context.go 中定义为:

// PureJSON serializes the given struct as JSON into the response body. // PureJSON, unlike JSON, does not replace special html characters with their unicode entities. func (c *Context) PureJSON(code int, obj any) { c.Render(code, render.PureJSON{Data: obj}) }

而渲染器 render/json.go 的PureJSON.Render做三件事:

  1. 写入Content-Type: application/json; charset=utf-8
  2. 通过当前 JSON codec 创建Encoder,调用encoder.SetEscapeHTML(false)
  3. 调用encoder.Encode(r.Data)

注意EncodeMarshal不同:它会"在 JSON 编码后追加一个换行符"(codec/json/api.go 的注释)。所以PureJSON的响应体比c.JSON多一个结尾换行,仓库测试 render_test.go 的期望值{"foo":"bar","html":"<b>"}后正是带\n的。

写一个最小示例并核对输出

下面这个程序直接取自 docs/doc.md 的 PureJSON 章节,同时挂上/json/purejson两条路由,方便对比转义前后的差异。保存为独立目录中的main.gogo mod init+go get github.com/gin-gonic/gin),然后运行:

package main import ( "net/http" "github.com/gin-gonic/gin" ) func main() { r := gin.Default() // Serves unicode entities r.GET("/json", func(c *gin.Context) { c.JSON(http.StatusOK, gin.H{ "html": "<b>Hello, world!</b>", }) }) // Serves literal characters r.GET("/purejson", func(c *gin.Context) { c.PureJSON(http.StatusOK, gin.H{ "html": "<b>Hello, world!</b>", }) }) // listen and serve on 0.0.0.0:8080 r.Run(":8080") }
go run .

启动后分别请求两条路由:

curl http://localhost:8080/json curl http://localhost:8080/purejson

判断标准以仓库测试断言为准:c.JSON"html": "<b>"的期望输出是转义形式"\u003cb\u003e"(context_test.go);c.PureJSON的期望输出是字面量"<b>",且Content-Typeapplication/json; charset=utf-8(context_test.go 的TestContextRenderPureJSON)。如果/json返回\u003c...\u003e/purejson返回<...>,说明行为与文档一致。

需要中断响应链时:AbortWithStatusPureJSON

如果你的场景是中间件里校验失败后要"中断链 + 返回未转义 JSON",可以用AbortWithStatusPureJSON。context.go 中的注释说明它先调用Abort()再内部调用PureJSON,停止处理链、写入状态码并返回不带转义的 JSON body,同时把Content-Type设为application/json。对应测试 TestContextAbortWithStatusPureJSON 断言了响应体未被转义({"foo":"fooValue","bar":"barValue"}形式的明文输出)且上下文处于 aborted 状态。

可选分支:替换 JSON codec 时 PureJSON 是否仍生效

Gin 默认用encoding/json,也可以按 docs/doc.md 的 Build Tags 章节在构建时替换 codec:

go build -tags=jsoniter . # 或 go build -tags=go_json . # 或 go build -tags=sonic .

PureJSON.Render不是直接调用encoding/json,而是走 codec 抽象的json.API.NewEncoder(w)SetEscapeHTML(false)(见上文 render/json.go)。各 codec 实现(如 codec/json/jsoniter.go 使用jsoniter.ConfigCompatibleWithStandardLibrary)都返回实现了同一Encoder接口的对象,该接口的SetEscapeHTML语义在 codec/json/api.go 中统一注明。因此按上述 build tag 替换 codec 构建时,PureJSON的关闭转义逻辑仍然走同一接口路径。

限制与核对清单

  • 文档明确说明:"This feature is unavailable in Go 1.6 and lower",即 PureJSON 需要 Go 1.6 以上;当前仓库要求 Go 1.25.0(go.mod),正常拉取构建即可满足。
  • PureJSON输出带一个结尾换行符(Encode行为),这是与c.JSON输出的已知差异,来自 codec/json/api.go 的注释与 render_test.go 的断言。
  • 两种渲染器Content-Type都是application/json; charset=utf-8,区别只在是否转义,不要依赖Content-Type来区分二者。
  • 不依赖跑服务也可以核对:在本仓库根目录执行go test -run TestRenderPureJSON ./render/go test -run TestContextRenderPureJSON .,两条测试分别对应渲染器与Context层的字面量输出断言。

如果你发现/purejson的输出仍被转义,先确认代码路径确实改成了c.PureJSON(而不是c.JSON);文档中AbortWithStatusPureJSON注释里 "return a JSON body without escaping" 的描述表明,未转义行为是纯PureJSON渲染路径的预期,而非配置项可切换的选项。

【免费下载链接】ginGin is a high-performance HTTP web framework written in Go. It provides a Martini-like API but with significantly better performance—up to 40 times faster—thanks to httprouter. Gin is designed for building REST APIs, web applications, and microservices.项目地址: https://gitcode.com/GitHub_Trending/gi/gin

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/10 22:58:19

pycharm使用小记__init__.py

什么时候在pycharm中建包需要__init__.py的包呢,什么时候不需要呢?? 官网链接中6.4包的解说 Python 包(Packages)详解 包是通过使用“带点号模块名”来构造 Python 模块命名空间的一种方式。 例如,模块名 A.B 表示名为 A 的包中名为 B 的子模块。 就像使用模块可以让不…

作者头像 李华
网站建设 2026/9/10 22:57:11

麻雀搜索算法优化LSSVM的多输出回归预测实战

做过多输出回归预测的人应该都有同感&#xff1a;单输出模型跑得再溜&#xff0c;一换到“一次输入、同时预测好几个相关指标”的场景&#xff0c;常常会碰一鼻子灰。比如根据风机的转速、功率、温度&#xff0c;同时预测未来几个时段的发电量&#xff1b;或者根据烟气参数&…

作者头像 李华
网站建设 2026/9/10 22:56:38

CANN/GE DT用例开发总纲

GE DT用例开发总纲 【免费下载链接】ge GE&#xff08;Graph Engine&#xff09;是面向昇腾的图编译器和执行器&#xff0c;提供了计算图优化、多流并行、内存复用和模型下沉等技术手段&#xff0c;加速模型执行效率&#xff0c;减少模型内存占用。 GE 提供对 PyTorch、TensorF…

作者头像 李华
网站建设 2026/9/10 22:55:27

机器学习入门:手写线性回归与房价预测实战

我入行时做的第一个真正意义上的机器学习模型&#xff0c;不是神经网络&#xff0c;而是线性回归。后来带新人&#xff0c;我也总是先让他们把线性回归从头撸一遍。不是因为简单&#xff0c;而是因为它把机器学习的核心逻辑全串在了一起&#xff1a;数据怎么处理、模型怎么定义…

作者头像 李华
网站建设 2026/9/10 22:54:33

CANN/ge图引擎节点构建API

Build 【免费下载链接】ge GE&#xff08;Graph Engine&#xff09;是面向昇腾的图编译器和执行器&#xff0c;提供了计算图优化、多流并行、内存复用和模型下沉等技术手段&#xff0c;加速模型执行效率&#xff0c;减少模型内存占用。 GE 提供对 PyTorch、TensorFlow 前端的友…

作者头像 李华
网站建设 2026/9/10 22:51:05

Scikit-learn入门:从数据预处理到模型部署全流程

1. 为什么选择Scikit-learn作为机器学习入门工具在数据科学和机器学习领域&#xff0c;Scikit-learn&#xff08;简称sklearn&#xff09;已经成为Python生态中最受欢迎的机器学习库之一。作为一个从业多年的数据科学家&#xff0c;我依然清晰记得第一次使用这个工具时的惊喜—…

作者头像 李华