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

在Gin框架中从中间件向路由传递CurrentUser结构体的问题

问题根源

你的panic是因为值类型与nil的不兼容:你定义的CurrentUser是结构体值类型,但中间件在未登录时执行了c.Set("currentUser", nil)——此时c.Get拿到的是interface{}类型的nil,而Go里值类型不能持有nil,尝试将这个nil断言为CurrentUser值类型必然触发panic。

下面提供两种可行的解决方案:


方案一:改用指针类型传递CurrentUser

这种方式贴合你原本用nil表示未登录的逻辑,是Go中更常用的写法:

1. 修改中间件代码

把user定义为指针类型,未登录时设置为nil指针:

func LoginMiddleware(database *sqlx.DB) gin.HandlerFunc {
    return func(c *gin.Context) {
        var (
            err    error
            cookie string
            user   *CurrentUser // 改为指针类型
        )

        cookie, err = c.Cookie("cookie")
        if err != nil {
            c.Set("currentUser", nil) // 未登录时设为nil指针
            c.Next()
            return
        }

        // 初始化指针并分配内存
        user = &CurrentUser{}
        err = database.Get(user, "SELECT user_id, username, email FROM users WHERE user_id = (SELECT user_id FROM sessions WHERE cookie = ?)", cookie)
        if err != nil {
            c.Set("currentUser", nil)
            c.Next()
            return
        }

        user.Cookie = cookie
        c.Set("currentUser", user)
        c.Next()
    }
}

2. 修改路由处理函数

断言为指针类型,并判断是否为nil来处理未登录情况:

func HandleProfileGet(c *gin.Context) {
    var (
        currentUser  *CurrentUser // 改为指针类型
        userSessions []SessionRow
        err          error
    )

    getCurrentUser, ok := c.Get("currentUser")
    if !ok {
        c.String(401, "Unauthorized")
        return
    }

    currentUser, ok = getCurrentUser.(*CurrentUser)
    if !ok || currentUser == nil {
        c.String(401, "Unauthorized")
        return
    }

    err = Database.Select(&userSessions, "SELECT session_id, user_id, cookie FROM sessions WHERE user_id = ?", currentUser.UserId)
    if err != nil {
        c.String(500, "Internal server error")
        return
    }

    c.HTML(200, "profile", gin.H{
        "CurrentUser":  currentUser,
        "UserSessions": userSessions,
    })
}

模板使用无需修改,直接通过{{.CurrentUser.Username}}访问即可,Go模板会自动处理指针。


方案二:保留值类型,添加登录状态标识

如果不想用指针,可以给CurrentUser新增一个IsLoggedIn字段,用它判断登录状态:

1. 修改CurrentUser结构体

type CurrentUser struct {
    UserId      int
    Username    string
    Email       string
    Cookie      string
    IsLoggedIn  bool // 新增字段,标识是否登录
}

2. 修改中间件代码

未登录时设置零值结构体并标记IsLoggedIn=false:

func LoginMiddleware(database *sqlx.DB) gin.HandlerFunc {
    return func(c *gin.Context) {
        var (
            err    error
            cookie string
            user   CurrentUser
        )

        cookie, err = c.Cookie("cookie")
        if err != nil {
            // 未登录时设置IsLoggedIn为false
            c.Set("currentUser", CurrentUser{IsLoggedIn: false})
            c.Next()
            return
        }

        err = database.Get(&user, "SELECT user_id, username, email FROM users WHERE user_id = (SELECT user_id FROM sessions WHERE cookie = ?)", cookie)
        if err != nil {
            c.Set("currentUser", CurrentUser{IsLoggedIn: false})
            c.Next()
            return
        }

        user.Cookie = cookie
        user.IsLoggedIn = true // 登录成功设为true
        c.Set("currentUser", user)
        c.Next()
    }
}

3. 修改路由处理函数

直接断言为值类型,通过IsLoggedIn判断登录状态:

func HandleProfileGet(c *gin.Context) {
    var (
        currentUser  CurrentUser
        userSessions []SessionRow
        err          error
    )

    getCurrentUser, ok := c.Get("currentUser")
    if !ok {
        c.String(401, "Unauthorized")
        return
    }

    currentUser, okType := getCurrentUser.(CurrentUser)
    if !okType || !currentUser.IsLoggedIn {
        c.String(401, "Unauthorized")
        return
    }

    err = Database.Select(&userSessions, "SELECT session_id, user_id, cookie FROM sessions WHERE user_id = ?", currentUser.UserId)
    if err != nil {
        c.String(500, "Internal server error")
        return
    }

    c.HTML(200, "profile", gin.H{
        "CurrentUser":  currentUser,
        "UserSessions": userSessions,
    })
}

模板中还可以用{{if .CurrentUser.IsLoggedIn}}来快速区分登录状态,渲染不同内容。


内容的提问来源于stack exchange,提问作者Fluffy Bean

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 08:59:51