模板加载必须在路由注册前完成,否则c.html()会panic;路径匹配需用**递归子目录;模板名仅取文件basename且大小写敏感;结构体字段必须首字母大写才可导出;url括号编码是标准行为,可用template.url绕过html转义。

模板加载必须在路由注册前完成
没加载模板就调用 c.HTML(),Gin 会直接 panic 报错 template is undefined,而不是返回空白页。这是最常踩的坑——很多人把 r.LoadHTMLGlob("templates/**/*") 放在 r.GET(...) 后面,或者夹在中间。
-
LoadHTMLGlob必须紧跟gin.Default()或gin.New()之后,且在任何r.GET/r.POST之前 - 路径
"templates/**/*"中的**表示递归子目录,*只匹配当前层;写成"templates/*.html"就漏掉templates/user/index.html - 编译后运行时,Gin 只认二进制文件所在目录下的
templates/,不是源码目录;用go run main.go时需确保终端工作目录正确
c.HTML() 的模板名必须与磁盘文件名(不含路径)完全一致
传参时填 "user/profile.html" 或 "profile.html" 看似差不多,但只有后者能命中 —— Gin 注册模板时只取文件 basename,不保留目录结构。
- 若模板实际路径是
templates/admin/dashboard.tmpl,c.HTML(200, "dashboard.tmpl", data)才有效 - 大小写敏感:
"Index.html"和"index.html"是两个不同模板 - 扩展名必须一致:注册了
.tmpl文件,就不能用"index.html"去渲染
传入数据必须字段可导出且类型匹配
模板里写 {{.Title}},但传的是 struct{ title string },结果页面空着不报错 —— 因为小写字段无法被 html/template 访问。
- 用
gin.H最省事:gin.H{"Title": "首页", "Items": []string{"A", "B"}} - 自定义结构体必须首字母大写字段:
type PageData struct { Title string; Items []string } - 嵌套结构体字段也得可导出:
type User struct { Name string; Profile struct{ Age int } }→ 模板中要写{{.Profile.Age}},不能写{{.Profile.age}}
URL 字符串里的括号被转成 %28/%29 不是 bug
看到 src="http://a.com/(data).jpg" 渲染成 src="http://a.com/%28data%29.jpg" 就慌着去禁用转义?别急 —— 这是 html/template 在 URL 上下文里做的标准百分号编码,符合 RFC 3986,浏览器能正确解析,CDN 和反向代理也认。
- 想保持原始字符?先确认是否真有必要;多数场景下
%28更安全可靠 - 若确定 URL 已校验可信,用
template.URL("http://a.com/(data).jpg")传入,模板中仍写{{.url}},它会跳过 HTML 转义但保留 URL 编码逻辑 -
template.URL不等于“不编码”,它只是告诉引擎:“别当 HTML 内容转义,按 URL 规则处理”
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











