gin不内置模板引擎,依赖html/template;loadhtmlglob路径通配符需写对,推荐r.loadhtmlglob("templates/*/.html"),同名模板须用{{define}}显式命名并以完整路径调用。

Gin 框架本身不内置模板引擎,而是直接复用 Go 标准库的 html/template,所以它的模板能力完全取决于你如何加载、组织和调用这些模板——不是“能不能”,而是“怎么加载才不踩坑”。
LoadHTMLGlob 路径通配符必须写对,否则模板根本不会被加载
很多人写 r.LoadHTMLGlob("templates/*.html") 后发现子目录里的模板渲染失败,是因为这个模式只匹配顶层文件;而写成 r.LoadHTMLGlob("templates/**/*") 又可能因路径中含非法字符(比如空格、非 UTF-8 文件名)导致 template.Must panic。
- 推荐明确后缀:用
r.LoadHTMLGlob("templates/**/*.tmpl")或r.LoadHTMLGlob("templates/**/*.html"),避免匹配到 .DS_Store 或备份文件 - 如果模板分散在多级目录且存在同名文件(如
users/index.tmpl和admin/index.tmpl),c.HTML(200, "index.tmpl", ...)会随机选一个——必须靠{{define "admin/index.tmpl"}}显式命名并用完整路径名调用 - Windows 下路径分隔符不影响匹配,但
**在某些旧版 Go(filepath.WalkDir +r.LoadHTMLFiles
c.HTML 第二个参数 name 是文件名(不含路径),不是磁盘路径
当你调用 c.HTML(200, "user/profile.tmpl", data),Gin 并不会去查 templates/user/profile.tmpl 这个路径,而是从已加载的所有模板中查找名为 "user/profile.tmpl" 的那个——这个“名字”是在解析时由文件系统路径推导出来的,不是字符串拼接。
- 如果你用
r.LoadHTMLGlob("templates/**/*")加载了templates/user/profile.tmpl,那它的模板名就是"user/profile.tmpl",可直接传入 - 但若用
r.LoadHTMLFiles("templates/user/profile.tmpl"),模板名仍是"user/profile.tmpl",不是"profile.tmpl" - 一旦有重名(比如两个
index.tmpl),Gin 不报错也不警告,只会用最后加载的那个,调试时很难发现
嵌套模板必须用 {{define}} + {{template}},不能靠文件路径自动继承
Gin 没有类似 Django 的 {% extends %} 或 Vue 的 <slot></slot> 自动机制。所谓“模板继承”,本质是 Go 原生 html/template 的 define/template 组合,需要手动定义区块、手动嵌入。
- 基础布局模板里写
{{define "layout"}}...{{template "content" .}}{{end}} - 子模板里写
{{define "content"}}<h1>Hello</h1>{{end}},再加一行{{template "layout" .}} - 渲染时仍需调用
c.HTML(200, "child.tmpl", data),而不是"layout.tmpl"——因为只有child.tmpl包含了template "layout"调用 - 所有
define名称必须全局唯一,重复定义会导致template: redefinition错误
最常被忽略的一点:模板函数(比如自定义的 safeHTML)必须在 template.Must 解析前注册;而 Gin 的 LoadHTMLGlob 内部调用的是 template.ParseGlob,不暴露底层 *template.Template 实例——所以想加函数,得自己用 template.New 构建再传给 r.SetHTMLTemplate。











