根本区别在于自动转义行为:html/template默认对插值做HTML实体转义,text/template完全不转义;渲染HTML必须用html/template,纯文本场景用text/template。

text/template 和 html/template 的核心区别在哪
根本区别不在语法,而在自动转义行为:html/template 默认对所有 .Value 插值做 HTML 实体转义(如 → zuojiankuohaophpcn),text/template 完全不转义。选错会导致 XSS 漏洞或页面显示乱码。
- 渲染纯文本日志、邮件正文、配置生成等场景,用
text/template - 渲染 HTML 页面、内联 JS/CSS 片段、响应前端的 HTML 内容,必须用
html/template - 两者 API 几乎一致,
template.ParseFiles、tmpl.Execute等调用方式完全相同
如何安全地在 html/template 中插入原始 HTML
直接写 {{.HTMLContent}} 会被转义成一堆 zuojiankuohaophpcndivyoujiankuohaophpcn —— 这不是 bug,是默认防护。要绕过转义,必须显式声明该值“已可信”:
func main() {
tmpl := template.Must(template.New("").Parse(`{{.SafeHTML}}`))
data := struct{ SafeHTML template.HTML }{
SafeHTML: template.HTML(`hello`),
}
tmpl.Execute(os.Stdout, data)
}
- 只能用
template.HTML类型包裹字符串,不能用string强转 -
template.JS、template.CSS、template.URL同理,用于对应上下文的安全注入 - 切勿把用户输入直接转成
template.HTML,这等于主动关闭 XSS 防护
模板中调用函数和方法要注意什么
两者都支持自定义函数和接收者方法,但函数注册逻辑一致,而方法调用受接收者类型限制:
func sayHi(name string) string { return "Hi, " + name }
tmpl := template.Must(template.New("t").Funcs(template.FuncMap{"hi": sayHi}))
tmpl.Parse(`{{hi .Name}}`) // ✅ 正确
- 函数名不能含点号(
.),否则Funcs会 panic - 结构体方法必须是导出(首字母大写),且接收者需为指针或值类型(不能是接口)
-
html/template中,函数返回值若为string仍会被转义;只有返回template.HTML等特殊类型才跳过转义
常见 panic 错误:template: xxx: unexpected “.” in operand
多因模板语法写错,比如漏掉空格、括号不匹配,或在 {{if}} 条件里用了非法表达式:
立即学习“go语言免费学习笔记(深入)”;
-
{{if .User.Name == ""}}✅ 合法(Go 模板支持简单比较) -
{{if .User.Name == nil}}❌ panic(nil 不可比较,改用{{if not .User.Name}}) -
{{range .Items}}{{.Name}{{end}}❌ 缺少右括号,报错位置常指向开头的. - 调试技巧:用
template.Must包裹Parse,让错误在加载时暴露,而非执行时静默失败
最易被忽略的是:同一个 *template.Template 实例不能并发调用 Execute,必须为每次请求克隆一份(tmpl.Clone())或创建新实例——否则可能 panic 或输出错乱。










