渲染纯文本用text/template,生成HTML必须用html/template;前者不转义适合配置、日志等场景,后者自动上下文感知转义防XSS,混用会导致安全漏洞或解析失败。

text/template 和 html/template 到底该用哪个?
渲染纯文本(如配置文件、日志模板、邮件正文)用 text/template;生成 HTML 页面或含 HTML 标签的输出,必须用 html/template。混用会出安全问题或解析失败。
关键区别不是“能不能用”,而是“该不该用”:
-
html/template对所有{{.Field}}输出自动做 HTML 转义(比如把<script></script>变成<script>),防止 XSS -
text/template完全不转义——传入"<b>hello</b>"就原样输出,适合 Markdown、YAML、Go 代码生成等场景 - 即使你只渲染一段 HTML 片段,只要最终会插入到浏览器里,就该用
html/template,否则用户提交的恶意内容会直接执行
模板文件找不到:ParseFiles 报 no such file or directory 怎么办?
错误信息通常是 open templates/base.html: no such file or directory,根本原因不是文件不存在,而是 Go 进程当前工作目录(os.Getwd())和模板路径不匹配。
不要依赖相对路径,也不要用 ./templates/xxx.html:
立即学习“go语言免费学习笔记(深入)”;
- 启动时用
os.Executable()获取二进制路径,再用filepath.Dir()拼出同级的templates/目录 - 示例:
t, err := template.ParseGlob(filepath.Join(filepath.Dir(execPath), "templates", "*.html")) - 开发调试时可临时加
os.Chdir("/your/project/root"),但上线前必须删掉 - 如果用
template.ParseFiles("a.html", "b.html"),任一文件缺失就返回 error,不会继续加载其余文件
嵌套模板里变量为空:{{template "header"}} 渲染不出 .Title 怎么办?
写 {{template "header"}} 是错的,它把空上下文传给子模板;正确写法是 {{template "header" .}},把当前数据完整传下去。
常见现象:父模板能访问 {{.Title}},子模板里却显示空白,甚至 panic。
-
.表示当前作用域的数据(结构体、map 或其他 interface{}),缺了它,子模板拿到的是 nil 或空 map - 所有
{{define}}名称在同一个*template.Template实例中全局唯一,重名会静默覆盖——建议用"layout-header"这类带前缀的命名 - 不能直接向
{{template}}传多个参数,如需定制数据,提前组织进结构体字段,比如.HeaderData
Execute 前漏设 Content-Type 导致页面变纯文本或 panic
用 http.ResponseWriter 输出 HTML 时,w.Header().Set("Content-Type", "text/html; charset=utf-8") 必须在 t.Execute(w, data) 之前调用。
漏掉这步的后果很具体:
- 浏览器没收到
Content-Type头,默认按text/plain解析,HTML 标签全变成可读文字 - 响应含中文时可能触发
http: invalid byte in bodypanic(尤其在 Windows 环境下) -
html/template的自动转义依赖于已知输出上下文,Content-Type 缺失会让某些内部判断失效
真正容易被忽略的点是:哪怕你用 template.HTML 绕过转义,也要确保原始字符串本身可信——这个绕过动作不会改变 Content-Type 缺失带来的解析问题。


















