站点图标 星露谷值班站长

gin-session中间件跳转以及个别页面session数据丢失问题解决

最近使用 go+gin 开发网站应用,在处理用户登录状态开发的过程中我选择使用 gin 官方提供的 session 解决方案,也就是 gin-contrib/sessions

项目地址: https://github.com/gin-contrib/sessions

中间件的使用也很简单,官方 demo 如下

package main

import (
  "github.com/gin-contrib/sessions"
  "github.com/gin-contrib/sessions/cookie"
  "github.com/gin-gonic/gin"
)

func main() {r := gin.Default()
  store := cookie.NewStore([]byte("secret"))
  r.Use(sessions.Sessions("mysession", store))

  r.GET("/hello", func(c *gin.Context) {session := sessions.Default(c)

    if session.Get("hello") != "world" {session.Set("hello", "world")
      session.Save()}

    c.JSON(200, gin.H{"hello": session.Get("hello")})
  })
  r.Run(":8000")
}

这个中间件用起来很好,但是也在使用过程中发现了一些问题。

最常见的问题就是登陆前和登陆后个别页面会出现 session 获取不到的情况。

问题演示: Gin 路由如下

	r.GET("/i/*name", func(c *gin.Context) {views.testViews(c)
	})

上面的路由 i /a i/b 其实都是走的一样的处理逻辑,我们使用中间件可以在登陆后获取和判断登录状态,但是往往就会出现没登陆时 i / a 是可以访问的,当我们登录之后 i /a 和 i / b 获取的 session 状态应该是一样的。但是真实的情况很可能出现 i / b 这个新访问页面是能够获取 session 状态的,而 i / a 却始终获取不到

问题的原因往往出现于 session 的设置上面,未登录时使用 session 设置的值 path 路径是当前页面而不是 / 所以也就会出现登陆后 session 取不到问题。

解决这个问题的方法也很简单,我们只需要在设置 session 的时候 Path 都设置为 / 就好了。

store, _ := redis.NewStoreWithDB(10, "tcp")
store.Options(sessions.Options{
	Path:   "/",
	MaxAge: 86400 * 90,
})
r.Use(sessions.Sessions("session", store))

在具体的逻辑处理里面不要单纯的只设置 MaxAge,要把 Path 也带上

session.Set("uuid", u4.String())
session.Options(sessions.Options{MaxAge: 86400 * 90, Path: "/"})
session.Save()

这样就不会出现一些页面能获取到一些页面获取不到 session 的问题了。

参考资料如下:

https://github.com/gin-contrib/sessions/issues/153

https://github.com/gin-contrib/sessions/issues/152

https://github.com/gin-contrib/sessions/issues/238

退出移动版