html/template 默认转义所有输出以防止 xss,需用 template.html 包装可信 html;嵌套字段访问要求导出且非 nil,应用 {{with}} 或 {{if}} 防 panic;多模板需 {{define}} + {{template}} 配合 executetemplate 调用。

html/template 不是为拼接 HTML 字符串设计的,它默认转义所有输出——这是安全底线,不是可选项。
为什么 template.Execute 渲染出一堆转义字符(比如 <div>)
<p>因为 <code>html/template 把所有 .Value 当作纯文本处理,除非你明确告诉它“这段内容是可信 HTML”。常见错误是直接传入字符串拼接的 HTML 片段,结果被双重转义。
- 用
template.HTML 类型包装原始 HTML:data := struct{ Content template.HTML }{Content: template.HTML("<b>OK</b>")}
- 不要用
fmt.Sprintf 或字符串拼接生成 HTML 后塞进普通 string 字段——那还是会被转义
- 若内容来自用户输入,绝不能转成
template.HTML,否则 XSS 漏洞直接上线
如何正确传参并访问嵌套字段(比如 .User.Profile.Avatar)
template.HTML 类型包装原始 HTML:data := struct{ Content template.HTML }{Content: template.HTML("<b>OK</b>")}
fmt.Sprintf 或字符串拼接生成 HTML 后塞进普通 string 字段——那还是会被转义template.HTML,否则 XSS 漏洞直接上线.User.Profile.Avatar)模板里点号链式访问依赖结构体字段必须是导出的(首字母大写),且中间任意一级不能为 nil。常见崩溃是 nil pointer dereference。
- 确保结构体字段全部导出:
type User struct { Profile *Profile },而不是profile *Profile - 在模板中用
{{with .User.Profile}}{{.Avatar}}{{end}}做非空判断,比直接{{.User.Profile.Avatar}}安全 - 如果字段是 map 或 slice,访问前也建议
{{if .Items}}或{{range .Items}},避免 panic
怎么加载多个模板文件(比如 layout + page + partial)
template.ParseFiles 和 template.ParseGlob 都只返回顶层模板,其他文件需用 {{template "name" .}} 显式调用——但前提是这些文件里已用 {{define "name"}} 声明过。
- 用
template.New("main").Funcs(...).ParseFiles("layout.html", "home.html")加载多个文件 - 在
layout.html里写{{define "layout"}}...{{template "content" .}}{{end}},在home.html里写{{define "content"}}<h1>{{.Title}}</h1>{{end}} - 执行时必须指定根模板名:
t.ExecuteTemplate(w, "layout", data),而不是t.Execute
最易被忽略的是:模板函数(Funcs)注册后,所有子模板都能用;但 template.HTML 只在当前作用域生效,跨 {{template}} 传递时仍需重新转换。











