html/template 的变量默认转义是安全机制而非 bug,{{.Content | safeHTML}} 是唯一推荐的绕过方式,需确保内容已校验过滤;禁用 text/template 替代,应采用服务端预处理或前端净化方案。

使用 html/template 时变量默认转义是安全机制,不是 bug
Go 的 html/template 在渲染时对所有变量输出自动做 HTML 转义(如 → <code><),这是防止 XSS 的核心设计。如果你发现内容被“变成乱码”或标签没生效,大概率不是框架出错,而是你本该输出 HTML 却没显式声明信任。
{{.Content | safeHTML}} 是唯一推荐的绕过方式
当变量内容确为可信 HTML(比如 CMS 后台编辑器存的富文本),必须用 safeHTML 过滤器显式标记:
- ✅ 正确:
{{.RawHTML | safeHTML}}—— 仅对已校验/过滤过的字段使用 - ❌ 错误:
{{.RawHTML}}—— 直接输出会转义成纯文本 - ❌ 危险:
{{.UserInput | safeHTML}}—— 用户输入绝不能跳过转义
注意:safeHTML 不做任何校验,它只是告诉模板引擎“这段我兜底”,一旦传入恶意脚本(如 <script>alert(1)</script>),XSS 立刻触发。
别用 text/template 替代 html/template 来“绕过转义”
有人试图换用 text/template 渲染 HTML 页面,以为能避免转义——这是严重误区:
-
text/template根本不提供 HTML 上下文感知,它连&、"都不转义,输出user.Name = "Alice & Bob"会直接破坏 HTML 结构 - 它无法防御属性上下文(如
<input value="{{.Value}}">)或 JS 上下文(如<script>var x = "{{.Data}}";</script>)中的注入 - Gin 默认绑定的是
html/template,强行切换需重写HTMLRender接口,得不偿失
更安全的替代方案:服务端预处理 + 前端渲染
如果大量富文本需要保留格式,又不想在模板层裸奔 safeHTML:
- 后端只返回纯净结构化数据(如 Markdown 字符串或 AST JSON)
- 前端用
marked、DOMPurify.sanitize()等库做二次解析与净化 - 或后端用
bluemonday库提前清洗 HTML,再传给模板:{{.CleanedHTML | safeHTML}}
真正容易被忽略的点是:safeHTML 的信任边界必须严格落在「已清洗」之后,而不是「已接收」之后。哪怕只漏掉一个 <img onerror="..." alt="Gin框架模板怎么避免变量被转义" >,整个防护就归零。


















