c.JSON() 返回纯JSON响应而不渲染HTML,适用于API;要在HTML中嵌入JSON需用c.HTML()配合json.RawMessage和|safe。

c.JSON() 不渲染到页面,它直接返回 JSON 响应体给客户端(比如前端 AJAX 请求),浏览器打开 URL 时看到的是纯 JSON 文本,不是“渲染进 HTML 页面”的效果。真要“把 JSON 数据塞进 HTML 页面里展示”,得走 c.HTML() + 模板变量这条路。
c.JSON() 是纯 API 响应,不是页面渲染
- 它设置 Content-Type 为
application/json,写入序列化后的 JSON 字节流,不经过任何 HTML 模板 - 浏览器直接显示原始 JSON(如
{"name":"Alice","age":30}),不会执行 JS、不加载 CSS、不解析 HTML 标签 - 前端用
fetch()或axios调它才合理;直接在地址栏敲 URL 看到的只是调试用的裸数据
想在 HTML 页面里显示 JSON 数据,用 c.HTML() 传参进模板
- Gin 的
c.HTML()把 Go 值(包括 map、struct、甚至json.RawMessage)作为数据传给模板,由{{ .FieldName }}插入 HTML - 如果你手头只有 JSON 字节(比如从第三方 API 拿来的
[]byte),别急着json.Unmarshal再转 struct,可以直接用json.RawMessage避免二次序列化:
func handler(c *gin.Context) {
rawJSON := []byte(`{"user":{"name":"Bob","score":95}}`)
var data json.RawMessage = rawJSON
c.HTML(http.StatusOK, "index.html", gin.H{
"payload": data, // 直接传,模板里 {{ .payload }} 就是原样 JSON 字符串
})
}
- 模板里可直接输出(注意加
safe):
<script>
const data = {{ .payload | safe }};
console.log(data.user.name); // Bob
</script>
- 别漏了
| safe,否则 Gin 默认 HTML 转义会把{变成{,JS 解析失败
容易踩的坑
-
c.JSON(200, someMap)和c.HTML(200, "t.html", someMap)语义完全不同:前者是接口,后者才是页面渲染 - 模板里用
{{ .Name }}取值时,字段必须首字母大写(Go 导出规则),否则模板收不到 - 传
json.RawMessage时,确保字节合法;非法 JSON 会导致模板渲染 panic,且错误不明显 - 不要用
fmt.Sprintf("%s", raw)拼接 JSON 字符串再传给模板——容易引号/转义错乱,json.RawMessage是标准解法
实际开发中,多数场景下 JSON 数据是给前端 JS 消费的,后端只管提供干净的 c.JSON() 接口;需要“页面内嵌 JSON”的情况,通常是为了初始化单页应用(SPA)状态,这时 json.RawMessage + | safe 是最轻量可控的方式。











