必须用html/template而非text/template防XSS;路径需用os.Executable()+filepath.Dir()定位;Execute前须设Content-Type;嵌套模板传参用{{template "name" .}}。

用 html/template 渲染页面不是“配个模板就能跑”,路径、Content-Type、字段导出、模板复用这四点不处理好,80% 的人会在 404、空白页、panic 或 XSS 漏洞里反复调试。
template.ParseFiles 找不到文件?工作目录不是源码目录
Go 进程启动时的当前工作目录(os.Getwd())决定 template.ParseFiles 查找路径的基准,和 .go 文件位置完全无关。常见现象是:go run main.go 在项目外执行,或构建后二进制挪了位置,直接报 open templates/index.html: no such file or directory。
- 最稳方案:用
os.Executable()+filepath.Dir()拼出二进制同级的templates/路径,例如:filepath.Join(filepath.Dir(execPath), "templates", "index.html") - 开发期可临时用
ParseGlob("templates/*.html"),但注意它不支持跨目录递归(**需 Go 1.16+ 且要确认 runtime 支持) - 绝对路径虽硬核,但部署路径易变,不推荐用于生产环境
-
ParseFiles返回的error必须检查——它不会静默失败,漏判就 panic
Execute 前没设 Content-Type,浏览器乱码或拒收
HTTP 响应头缺 Content-Type,浏览器可能把 UTF-8 HTML 当成 ISO-8859-1 解析,中文全变方块;更糟的是某些浏览器直接拒收响应体,页面空白无报错。
- 必须在
tpl.Execute(w, data)前加:w.Header().Set("Content-Type", "text/html; charset=utf-8") - 如果模板里混了非 UTF-8 字符(比如从旧数据库读出的 GBK 内容),
Execute会 panic,得先转码 - 传给
Execute的data不能是nil,哪怕空结构体也得初始化,否则 panic
嵌套模板传参为空?漏写了 . 后缀
写 {{template "header"}} 是把空上下文传进去,子模板拿不到父模板的数据。很多新手卡在“变量明明定义了却渲染为空”。
立即学习“go语言免费学习笔记(深入)”;
- 必须写成
{{template "header" .}},那个.表示将当前作用域完整数据传给子模板 - 子模板里仍可用
{{.Title}}、{{.Items}},和父模板一致 - 所有
{{define}}名称在同一个*template.Template实例中全局唯一;重名会静默覆盖,建议按文件名+区块名组合命名,如"index-body" - 不支持直接向
{{template}}传多个参数;如需定制,应提前把数据组织进结构体字段或map子键
为什么必须用 html/template 而不是 text/template
这不是“功能差异”,是安全红线。text/template 渲染用户输入内容(比如评论、昵称),{{.Content}} 会原样插入 <script></script>,浏览器直接执行。
- 所有 Web 页面渲染必须用
import "html/template" - 只有当你明确需要注入已审核的富文本(如 CMS 后台编辑器输出),才通过自定义函数返回
template.HTML类型,例如:{{.SafeContent | safeHTML}} - 自定义
safeHTML函数必须注册到FuncMap,且内部不做任何过滤——信任必须由上游业务层保证,模板层不承担净化责任 - 导入时别手快写成
"text/template",编译不报错,运行时才暴露问题
真正难的不是语法,是模板解析时机和数据边界——解析必须在启动时完成,业务计算必须前置到 Go 层,模板里只做纯展示。改一个字段名、换一个路径拼法、少设一次 Header,都可能让整个页面在生产环境静默失效。


















