基于 gorilla/sessions 包在 Go 语言中启动和管理 Session


Go 语言官方提供的 http 包虽然对 HTTP 编程提供了丰富的 API,但是没有提供官方的 Session 实现。如果在 Web 应用中使用到了 Session,需要自行去实现(就像在线论坛这个入门项目中所做的那样),或者使用第三方工具包,比如 gorilla/sessions,这里我们以后者为例演示如何通过它在 Go Web 应用中启动和管理 Session。

gorilla/sessions 内置了基于 Cookie 和文件系统作为存储引擎的 Session 实现,此外,还为其他后端自定义 Session 存储驱动提供了底层接口(比如 Memcache、Redis、MySQL、MongoDB、PostgreSQL、CockroachDB 等,更多第三方驱动实现请参考项目官方文档)。

下面我们基于 gorilla/sessions 通过 Session 来实现一个简单的计数器,这里我们使用 Cookie 作为存储器。新建一个 counter 目录,运行 go mod init demo/counter 进行模块初始化 :

-w555

然后在该目录下编写计数器服务端实现代码 main.go

package main

import (
    "github.com/gorilla/sessions"
    "html/template"
    "log"
    "net/http"
    "os"
)

// 初始化存储器(基于 Cookie)
var store = sessions.NewCookieStore([]byte(os.Getenv("SESSION_KEY)")))

func counter(w http.ResponseWriter, r *http.Request)  {
    session, _ := store.Get(r, "GOSESSID")
    count := session.Values["count"];
    if count == nil {
        session.Values["count"] = 1
    } else {
        session.Values["count"] = count.(int) + 1
    }
    err := session.Save(r, w)
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
    t, _ := template.ParseFiles("counter.gtpl")
    w.Header().Set("Content-Type", "text/html")
    t.Execute(w, session.Values["count"])
}

func main()  {
    http.HandleFunc("/counter", counter)
    err := http.ListenAndServe(":8888", nil)
    if err != nil {
        log.Fatal("ListenAndServe: ", err)
    }
}

运行 go mod tidy 自动下载依赖。

通过上述源码可以看到,要基于 gorilla/sessions 管理 Session,首先要初始化一个 Session 存储器,这里我们使用 sessions.NewCookieStore 创建一个基于 Cookie 的 Session 存储器,并且通过系统变量传入 SESSION_KEY 进行认证。

在具体某个 Web 路由处理器方法中使用 Session(这里是处理 /counter 路由的 counter 处理器方法),可以通过 store.Get 方法获取或者创建一个新的 Session 对象(通过 GOSESSID 进行标识),然后我们试图通过 session.Values["count"] 从这个 Session 对象上获取存储在其中的 count 变量值,如果值为空,将其初始化为 1,否则在原来的基础上加 1,从而实现计数器的功能。最后,我们通过 session.Save 方法保存 Session 更改。

注:session.Values 是一个字典结构(map[interface{}]interface{}),所以可以向其中添加任意多个键值对存储信息。

我们通过 counter.gtpl 作为页面模板来渲染这个计数器视图,并且将 Session 中存储的 count 值传递给该视图模板。

counter 目录下创建这个 counter.gtpl 并编写一段简单的视图模板代码:

<h1>当前计数器的值:{{ . }}</h1>

运行 go run main.go 启动计数器服务(不要忘了传递 SESSION_KEY 系统变量):

-w682

然后在浏览器中就可以通过 http://localhost:8888/counter 访问这个计数器了:

-w650

每次刷新页面,计数器的值都会 +1:

-w537

打开浏览器开发者工具,在 Application | Storage | Cookies 中可以看到存储在 Cookie 中的 Session 信息(加密过),其默认有效期是 1 个月:

-w1100

如果我们删除这个 Cookie,则 Session 数据会清空,计数器归零,刷新页面,计数器的值恢复成 1:

-w712

我们还可以将上述 Cookie 存储调整为文件存储:

// 初始化存储器
var store = sessions.NewFilesystemStore("session", []byte(os.Getenv("SESSION_KEY)")))

counter 目录下新建一个 session 子目录,重启服务,访问 http://localhost:8888/counter,可以看到 session 目录下现在会创建对应的 Session 文件:

-w667

由于 Session 本身需要依赖 Cookie 存储 Session ID,所以在开发者工具中依然会包含名为 GOSESSID 的 Cookie 信息。

你还可以通过存储对象提供的 API 设置 Session 有效期,通过 Session 对象设置一次性消息(Flash Message),更多细节,请查看 gorilla/sessions 包底层源码。


Vote Vote Cancel Collect Collect Cancel

<< 上一篇: 在 Go 语言中设置、读取和删除 HTTP Cookie

>> 下一篇: Go 视图模板篇(一):模板引擎的定义、解析与执行