template.ParseFiles 路径基于 os.Getwd() 而非代码目录,应使用 filepath.Join(filepath.Dir(runtime.Caller(0)), "x.tmpl") 或 embed.FS + ParseFS;自定义函数须在 Parse 前用 Funcs 注册;HTML 转义需 safeHTML 显式标记;{{define}} 名称严格匹配,用 Templates() 检查。

template.ParseFiles 读不到文件?路径是相对的,不是相对于项目根目录
Go 的 template.ParseFiles 默认以当前工作目录(os.Getwd() 返回的路径)为基准找文件,不是代码所在目录,也不是 go run 所在目录——这导致本地能跑、CI 或 Docker 里报 open xxx: no such file or directory。
- 用
filepath.Join(filepath.Dir(runtime.Caller(0)), "xxx.tmpl")获取模板文件的绝对路径再传给ParseFiles - 或者统一把模板放在
embed.FS里(Go 1.16+),用template.ParseFS更可靠 - 调试时先打印
os.Getwd()和filepath.Abs("xxx.tmpl"),确认路径是否真存在
模板里调用函数报 function "xxx" not defined
Go 模板默认只内置几个函数(如 print、len),自定义函数必须显式注册,且注册时机必须在 Parse 之前。
- 用
tmpl := template.New("").Funcs(template.FuncMap{"toUpper": strings.ToUpper})注册 - 如果用了
template.Must(tmpl.Parse(...)),确保Funcs调用在Parse前,顺序错就无效 - 函数签名必须是 Go 可导出的:首字母大写 + 参数/返回值类型明确(不能有未导出类型)
- 注意函数名大小写:模板里写
{{toUpper .Name}},不是{{ToUpper .Name}}—— 函数名按注册时的 key 匹配
HTML 自动转义导致标签被显示成纯文本
text/template 默认对所有 {{.XXX}} 输出做 HTML 转义,这是安全设计,但有时你确实需要渲染原始 HTML(比如富文本内容)。
- 用
{{.Content | safeHTML}}显式标记可信内容(safeHTML是内置函数) - 别用
strings.ReplaceAll之类手动拼接 HTML 字符串再塞进模板——绕过转义会埋 XSS 风险 - 如果整个模板都不想转义,改用
html/template包(它和text/templateAPI 几乎一样,但默认适配 HTML 上下文) - 注意:
safeHTML不校验内容合法性,只取消转义;前端仍需做 CSP 等防护
嵌套模板 {{define}} 不生效?ExecuteTemplate 名字要完全一致
定义了 {{define "header"}},却在 ExecuteTemplate 里传 "Header" 或 " layout/header ",就会静默失败,输出空内容。
立即学习“go语言免费学习笔记(深入)”;
- 模板名是严格字符串匹配,区分大小写、空格、斜杠
- 用
tmpl.Templates()查看已加载的所有模板名,确认拼写(返回[]*template.Template,每个的Name()就是定义名) - 多个
{{define}}在同一个template.Template实例里才可互相引用;跨文件需用template.ParseFiles一次性加载,或用template.Clone()共享函数和定义 - 常见陷阱:用
template.New("a").Parse(...)和template.New("b").Parse(...)分开解析,它们彼此隔离,b无法引用a里定义的模板
模板变量作用域、嵌套执行顺序、函数注册时机——这些地方不报错,但结果不对,得靠日志和 tmpl.DefinedTemplates() 一层层查。别信“应该可以”,直接打印出来看。


















