Gin模板渲染需显式加载文件或目录,否则c.HTML()会panic;必须在路由注册前调用LoadHTMLFiles/LoadHTMLGlob;数据须为gin.H或导出字段struct;HTML转义默认开启,需safe函数或template.HTML绕过;嵌套模板依赖{{define}}/{{template}};模板修改后需重启服务。

模板渲染在 Gin 中不是开箱即用的,必须显式加载文件或目录,否则 c.HTML() 会 panic 报错 “template not found”。
模板文件必须先用 LoadHTMLFiles 或 LoadHTMLGlob 加载
很多人写完 c.HTML() 就跑,结果 500 错误,日志里只有 html/template: "index.html" is undefined。这是因为 Gin 不会自动扫描目录——它压根不知道你有模板文件。
-
r.LoadHTMLFiles("templates/index.html", "templates/user.html"):适合模板少、路径明确的场景 -
r.LoadHTMLGlob("templates/**/*"):推荐用于多级目录(如templates/admin/dashboard.html),**表示递归匹配子目录 - 注意路径是运行时相对路径,不是源码路径;如果用
go run main.go,工作目录就是main.go所在目录 - 加载必须在任何路由注册前完成,放在
r := gin.Default()后、r.GET(...)前
c.HTML() 的第三个参数必须是 gin.H 或自定义 struct,不能传原始 map
Go 的 html/template 要求数据是导出字段(首字母大写)的 struct 或 gin.H(它是 map[string]interface{} 的别名,且 Gin 内部做了字段导出适配)。直接传 map[string]string{} 会导致模板里所有 .xxx 都为空。
- 正确写法:
c.HTML(200, "index.html", gin.H{"Title": "Home", "Items": []string{"a", "b"}}) - 错误写法:
c.HTML(200, "index.html", map[string]string{"title": "Home"})(title小写,模板无法访问) - 若用 struct,字段必须大写:
type PageData struct { Title string; Content string }
HTML 转义默认开启,要输出原始 HTML 必须用 template.HTML + 自定义函数
比如你想在模板里渲染一段带标签的富文本: Hello{{ .Content }} 会变成转义后的 ,浏览器显示为纯文本。这不是 bug,是 html/template 的安全机制。
- 解决方法一(推荐):在加载模板前注册安全函数:
r.SetFuncMap(template.FuncMap{"safe": func(s string) template.HTML { return template.HTML(s) }}),模板中写{{ .Content | safe }} - 解决方法二:用
template.HTML类型构造数据,例如gin.H{"Content": template.HTML("Hello
")} - 注意:
SetFuncMap必须在LoadHTMLFiles/Glob之前调用,否则无效
嵌套模板需手动定义 base.html 并用 {{ template }} 引入子内容
Gin 本身不提供类似 Django 的 {% extends %} 语法,但底层用的是 Go 标准 html/template,所以支持 {{ define }} 和 {{ template }} 组合。
- 基础模板
templates/base.html中写:{{ define "base" }}...{{ template "content" . }}...{{ end }} - 子模板
templates/index.html中写:{{ define "content" }}{{ .Title }}
{{ end }} - 渲染时仍用
c.HTML(200, "base.html", data),但必须确保两个文件都被LoadHTMLGlob加载到同一命名空间 - 常见坑:子模板没
{{ define "xxx" }},或 base 模板里{{ template "xxx" . }}名字拼错,都会静默失败(页面空白)
最易被忽略的一点:模板加载是一次性行为,修改模板文件后必须重启服务;热重载需要额外工具(如 air)或自己监听 fs 事件重新调用 LoadHTMLGlob —— Gin 默认不支持。











