模板无法访问*gin.Context,所有请求数据(如参数、Header、Cookie、中间件存的c.Set()值)必须在handler中提前用c.Param()、c.GetHeader()、c.Get()等提取,并显式传入c.HTML()的data参数中,模板仅渲染已提供的快照数据。

模板里根本拿不到 c *gin.Context
这是最常被误解的一点:Gin 的 html/template 渲染阶段完全脱离 gin.Context 生命周期。模板文件(比如 index.html)只接收你通过 c.HTML() 显式传入的数据,它无法调用 c.Param()、c.GetHeader() 或访问 c.Keys —— 因为 c 这个变量压根没传进去。
必须在 handler 中提前提取并注入私有数据
所谓“私有上下文”,比如用户 ID、登录态、请求路径、自定义中间件写入的 c.Set("tenant_id", "abc"),都得在渲染前手动取出,再塞进 gin.H 或结构体里:
- 用
c.Get("tenant_id")拿中间件存的值,别直接在模板里幻想有.Context.TenantID - 用
c.Request.URL.Path或c.FullPath()获取路径,而不是想在模板里调.Request.URL.Path - 如果用了
c.SetCookie()或c.GetHeader(),这些 Header/Cookie 值也得提前读出来,作为字段传入 - 避免传整个
*gin.Context(编译都过不了),Go 模板不接受指针或未导出字段的 struct
gin.H 和结构体传参的区别与风险
gin.H(即 map[string]interface{})写起来快,但容易在模板里拼错 key 导致静默空值;结构体类型安全,但字段必须首字母大写(导出)才能被模板访问:
-
gin.H{"user_id": uid, "is_admin": true}→ 模板用{{.user_id}},拼错 key 不报错 - 结构体:
type PageData struct { UserID string `json:"user_id"` IsAdmin bool `json:"is_admin"` }→ 模板用{{.UserID}},字段名错会编译/运行时报错 - 别传
map[string]any或嵌套太深的 map,模板里{{.Meta.Config.Env}}容易 panic
想复用模板时怎么带上下文?
没有“全局上下文注入”机制。每个 c.HTML() 调用都是独立的,哪怕共用同一个 index.html,你也得在每个 handler 里重新组装数据:
- 不要指望
LoadHTMLGlob()或模板{{template}}语法能自动继承上下文 - 可以封装一个函数,比如
renderPage(c *gin.Context, tmpl string, data interface{}),统一提取tenant_id、user_id等公共字段,再 merge 到data里 - 如果大量页面都需要用户信息,建议定义一个基础结构体,每次 embed 或匿名组合,而不是靠模板逻辑判断
最容易被忽略的是:模板里所有 “上下文” 都是快照,不是活引用。你在 handler 里改了 c.Set("foo", "bar"),但没把它传进 c.HTML() 的 data 里,那模板里就永远看不到 foo。


















