You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过Gin中间件向HTML模板传递通用数据(Golang)

在Gin框架中通过中间件全局传递模板数据

当然可以通过Gin的中间件实现全局传递分类数据,无需在每个处理器中重复编写代码,以下是具体实现方案:

1. 编写全局分类中间件

先实现一个中间件,负责获取分类数据并存储到Gin Context的Keys中,后续的处理器和渲染逻辑都能访问到该数据:

import (
    "sync"
    "github.com/gin-gonic/gin"
)

// 假设你的分类结构体定义如下
type Category struct {
    ID   uint
    Name string
}

var cachedCategories []Category
var cacheMutex sync.RWMutex

// CategoriesMiddleware 全局分类中间件,内置缓存优化避免重复查库
func CategoriesMiddleware(db *YourDBType) gin.HandlerFunc {
    return func(c *gin.Context) {
        // 优先从缓存读取分类数据
        cacheMutex.RLock()
        categories := cachedCategories
        cacheMutex.RUnlock()

        // 缓存为空时,从数据库拉取并更新缓存
        if categories == nil {
            cacheMutex.Lock()
            // 双重检查锁防止并发重复查库
            if cachedCategories == nil {
                cachedCategories = db.GetCategories()
            }
            categories = cachedCategories
            cacheMutex.Unlock()
        }

        // 将分类数据存入Context
        c.Set("categories", categories)
        // 执行后续中间件与处理器
        c.Next()
    }
}

将中间件注册到全局路由:

r := gin.Default()
// 传入你的数据库实例
r.Use(CategoriesMiddleware(yourDBInstance))

2. 自动合并全局数据到模板

有两种常用方式让模板自动获取Context中的分类数据:

方式一:自定义渲染函数(推荐)

封装自定义HTML渲染函数,自动合并Context中的分类数据与处理器传入的页面专属数据,无需手动重复添加:

// RenderHTML 自定义模板渲染函数,自动注入全局分类数据
func RenderHTML(c *gin.Context, status int, templateName string, data gin.H) {
    // 从Context取出分类数据
    categories, exists := c.Get("categories")
    if exists {
        // 仅当处理器未传入categories时才注入,避免覆盖自定义数据
        if _, hasCategory := data["categories"]; !hasCategory {
            data["categories"] = categories
        }
    }
    // 调用Gin原生HTML渲染逻辑
    c.HTML(status, templateName, data)
}

处理器中直接使用该函数,只需传入页面专属数据:

func HomeHandler(c *gin.Context) {
    RenderHTML(c, 200, "home.html", gin.H{
        "title": "博客首页",
        "posts": getHomePagePosts(),
    })
}

方式二:模板函数直接读取Context

若不想自定义渲染函数,可在模板中注册函数直接从Context获取分类数据:

初始化模板时注册函数:

r.SetFuncMap(template.FuncMap{
    "getGlobalCategories": func(c *gin.Context) []Category {
        cat, _ := c.Get("categories")
        return cat.([]Category)
    },
})

模板中直接调用该函数:

<!-- 导航栏分类下拉菜单 -->
<div class="dropdown">
    <button>分类</button>
    <div class="dropdown-content">
        {{ range getGlobalCategories . }}
            <a href="/category/{{ .ID }}">{{ .Name }}</a>
        {{ end }}
    </div>
</div>

注意事项

  • 若分类数据会更新,需添加缓存刷新逻辑(如定时任务或更新分类时主动清空缓存)
  • 中间件中数据库查询需添加错误处理,避免因DB异常阻塞请求

内容的提问来源于stack exchange,提问作者Ali Alhajji

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 07:58:30