c.JSON 输出细节(HTML 转义、PureJSON)
结论先行
c.JSON 输出 application/json; charset=utf-8,内部走 encoding/json,默认转义 HTML 特殊字符(< > & 会变成 \u003c 等)以降低 XSS 风险。想原样输出 <b> 这类内容用 c.PureJSON;想非 ASCII 全部转成 \uXXXX 用 c.AsciiJSON。
渲染方法对比
| 方法 | 行为 | 典型场景 |
|---|---|---|
| c.JSON(code, obj) | encoding/json 默认序列化,转义 HTML 字符 | 普通 API,绝大多数场景 |
| c.PureJSON(code, obj) | 关闭 HTML 转义,原样输出 | 响应内容含可信 HTML/富文本片段 |
| c.AsciiJSON(code, obj) | 非 ASCII 转 \uXXXX | 兼容只认 ASCII 的旧客户端 |
| c.IndentedJSON(code, obj) | 带缩进的 JSON | 调试、教学输出 |
| c.JSONP(code, obj) | 输出 callback 包裹,需防注入 | 跨域 JSONP 老接口(新项目慎用) |
使用细节
- 状态码与 body 一起给:
c.JSON(http.StatusOK, obj);第一个参数就是状态码。 - 一次请求只能成功写一次响应:状态码一旦提交,再调 c.JSON 只是往 body 里追加非法内容(详见第 25 章)。
- 字段输出受 json tag 控制;time.Time 默认 RFC3339 格式,想改格式就实现 MarshalJSON。
- gin.H 是 map[string]any 的别名,适合手拼小对象。
- 序列化失败时(如不可序列化类型),Gin 会打日志但响应已无法回退为错误 JSON。
代码示例
c.JSON(http.StatusOK, gin.H{"msg": "<b>hi</b> & bye"})
// 实际输出: {"msg":"\u003cb\u003ehi\u003c/b\u003e \u0026 bye"}
c.PureJSON(http.StatusOK, gin.H{"msg": "<b>hi</b> & bye"})
// 实际输出: {"msg":"<b>hi</b> & bye"}
c.AsciiJSON(http.StatusOK, gin.H{"msg": "你好"})
// 实际输出: {"msg":"\u4f60\u597d"}
常见追问 / 记忆点
- 追问:为什么 JSON 要默认转义 HTML?答:历史原因——JSON 常被嵌入 HTML/脚本上下文,转义 < > & 可防止内容被当作标签或破坏结构,属于纵深防御。
- 追问:PureJSON 与 JSON 性能差别?答:同一套编码器实现,仅是转义开关差异;别为“好看”在生产随意用 PureJSON 输出不可信内容。
- 记忆点:JSON 转义 HTML、Pure 不转义、Ascii 转非 ASCII;响应只能写一次,状态码先定。