gin模板无法访问gin.context,只能通过c.html()传入结构体或gin.h;所有请求数据(如参数、header、cookie)须在handler中提前提取并显式传入,模板仅负责渲染已提供的数据。

模板里拿不到 c *gin.Context,只能传进去
Gin 的 HTML 模板(html/template)运行在服务端渲染阶段,它**不持有也不访问** *gin.Context 对象。你不能在 {{ . }} 或 {{ .Request }} 里直接调用 c.Param、c.GetHeader 这类方法 —— 模板里没有 c 这个变量,只有你显式传进去的结构体或 map。
c.HTML() 传参必须是结构体或 gin.H
你在 handler 里调用 c.HTML(status, "page.html", data) 时,data 就是模板的根对象(.)。它只能是:
- 一个自定义结构体(推荐,类型安全)
-
gin.H(即map[string]interface{},写得快但易出错) - 原始值如
string、int(极少用,模板里只能用{{ . }})
例如,想把当前用户 ID 和请求路径传进模板:
r.GET("/profile/:id", func(c *gin.Context) {
userID := c.Param("id")
path := c.Request.URL.Path
c.HTML(200, "profile.html", gin.H{
"UserID": userID,
"Path": path,
"Title": "用户档案",
})
})
模板中就只能写 {{ .UserID }}、{{ .Title }},不能写 {{ .Param "id" }}。
需要动态请求信息?提前取好再传,别想“模板里实时查”
常见误区:以为模板能像 JS 那样调用函数获取 header、query 或 cookie。不行。所有依赖请求上下文的数据,都得在 handler 里取完、处理好、再作为字段塞进 data:
- 要显示
Authorization头?用c.GetHeader("Authorization")取,别传整个c.Request.Header - 要判断是否登录?中间件里
c.Set("user", user),handler 中user, _ := c.Get("user"),再传给模板 - 要渲染不同语言?从
c.GetHeader("Accept-Language")解析后传"lang": "zh-CN",而不是让模板去解析 header 字符串
模板不是执行环境,只是数据投影器。它的职责是“怎么画”,不是“从哪拿”。
复杂场景下容易漏掉的点:嵌套结构和 nil 安全
如果传的是结构体,字段名必须首字母大写(否则模板无法访问),且注意 nil 指针 panic:
type PageData struct {
UserID string
User *User // 如果 User 是 nil,{{ .User.Name }} 会 panic
}
模板里得加判空:{{ if .User }}{{ .User.Name }}{{ end }}。更稳妥的做法是提前展开或用 gin.H 做防御性赋值:
c.HTML(200, "page.html", gin.H{
"UserName": user.Name,
"IsAdmin": user.Role == "admin",
"AvatarURL": user.AvatarURL(),
})
真正麻烦的从来不是语法,而是忘记「模板没上下文」这个前提 —— 所有依赖请求状态的逻辑,都得在进入模板前收口完毕。











