基于 gorilla/sessions 在 Go 語(yǔ)言中管理 Session
Go 語(yǔ)言官方提供的 http 包雖然對(duì) HTTP 編程提供了豐富的 API,但是沒(méi)有提供官方的 Session 實(shí)現(xiàn)。如果在 Web 應(yīng)用中使用到了 Session,需要自行去實(shí)現(xiàn)(就像在線(xiàn)論壇這個(gè)入門(mén)項(xiàng)目中所做的那樣),或者使用第三方工具包,比如 gorilla/sessions,這里我們以后者為例演示如何通過(guò)它在 Go Web 應(yīng)用中啟動(dòng)和管理 Session。
gorilla/sessions 內(nèi)置了基于 Cookie 和文件系統(tǒng)作為存儲(chǔ)引擎的 Session 實(shí)現(xiàn),此外,還為其他后端自定義 Session 存儲(chǔ)驅(qū)動(dòng)提供了底層接口(比如 Memcache、Redis、MySQL、MongoDB、PostgreSQL、CockroachDB 等,更多第三方驅(qū)動(dòng)實(shí)現(xiàn)請(qǐng)參考項(xiàng)目官方文檔)。
下面我們基于 gorilla/sessions 通過(guò) Session 來(lái)實(shí)現(xiàn)一個(gè)簡(jiǎn)單的計(jì)數(shù)器,這里我們使用 Cookie 作為存儲(chǔ)器。新建一個(gè) counter 目錄,運(yùn)行 go mod init demo/counter 進(jìn)行模塊初始化 :

然后在該目錄下編寫(xiě)計(jì)數(shù)器服務(wù)端實(shí)現(xiàn)代碼 main.go:
package?main
import?(
????"github.com/gorilla/sessions"
????"html/template"
????"log"
????"net/http"
????"os"
)
//?初始化存儲(chǔ)器(基于?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)
????}
}
運(yùn)行 go mod tidy 自動(dòng)下載依賴(lài)。
通過(guò)上述源碼可以看到,要基于 gorilla/sessions 管理 Session,首先要初始化一個(gè) Session 存儲(chǔ)器,這里我們使用 sessions.NewCookieStore 創(chuàng)建一個(gè)基于 Cookie 的 Session 存儲(chǔ)器,并且通過(guò)系統(tǒng)變量傳入 SESSION_KEY 進(jìn)行認(rèn)證。
在具體某個(gè) Web 路由處理器方法中使用 Session(這里是處理 /counter 路由的 counter ?處理器方法),可以通過(guò) store.Get 方法獲取或者創(chuàng)建一個(gè)新的 Session 對(duì)象(通過(guò) GOSESSID 進(jìn)行標(biāo)識(shí)),然后我們?cè)噲D通過(guò) session.Values["count"] 從這個(gè) Session 對(duì)象上獲取存儲(chǔ)在其中的 count 變量值,如果值為空,將其初始化為 1,否則在原來(lái)的基礎(chǔ)上加 1,從而實(shí)現(xiàn)計(jì)數(shù)器的功能。最后,我們通過(guò) session.Save 方法保存 Session 更改。
注:
session.Values是一個(gè)字典結(jié)構(gòu)(map[interface{}]interface{}),所以可以向其中添加任意多個(gè)鍵值對(duì)存儲(chǔ)信息。
我們通過(guò) counter.gtpl 作為頁(yè)面模板來(lái)渲染這個(gè)計(jì)數(shù)器視圖,并且將 Session 中存儲(chǔ)的 count 值傳遞給該視圖模板。
在 counter 目錄下創(chuàng)建這個(gè) counter.gtpl 并編寫(xiě)一段簡(jiǎn)單的視圖模板代碼:
<h1>當(dāng)前計(jì)數(shù)器的值:{{ . }}h1>
運(yùn)行 go run main.go 啟動(dòng)計(jì)數(shù)器服務(wù)(不要忘了傳遞 SESSION_KEY 系統(tǒng)變量):

然后在瀏覽器中就可以通過(guò) http://localhost:8888/counter 訪(fǎng)問(wèn)這個(gè)計(jì)數(shù)器了:

每次刷新頁(yè)面,計(jì)數(shù)器的值都會(huì) +1:

打開(kāi)瀏覽器開(kāi)發(fā)者工具,在 Application | Storage | Cookies 中可以看到存儲(chǔ)在 Cookie 中的 Session 信息(加密過(guò)),其默認(rèn)有效期是 1 個(gè)月:

如果我們刪除這個(gè) Cookie,則 Session 數(shù)據(jù)會(huì)清空,計(jì)數(shù)器歸零,刷新頁(yè)面,計(jì)數(shù)器的值恢復(fù)成 1:

我們還可以將上述 Cookie 存儲(chǔ)調(diào)整為文件存儲(chǔ):
//?初始化存儲(chǔ)器
var?store?=?sessions.NewFilesystemStore("session",?[]byte(os.Getenv("SESSION_KEY)")))
在 counter 目錄下新建一個(gè) session 子目錄,重啟服務(wù),訪(fǎng)問(wèn) http://localhost:8888/counter,可以看到 session 目錄下現(xiàn)在會(huì)創(chuàng)建對(duì)應(yīng)的 Session 文件:

由于 Session 本身需要依賴(lài) Cookie 存儲(chǔ) Session ID,所以在開(kāi)發(fā)者工具中依然會(huì)包含名為 GOSESSID 的 Cookie 信息。
你還可以通過(guò)存儲(chǔ)對(duì)象提供的 API 設(shè)置 Session 有效期,通過(guò) Session 對(duì)象設(shè)置一次性消息(Flash Message),更多細(xì)節(jié),請(qǐng)查看 gorilla/sessions 包底層源碼。
(全文完)
推薦閱讀
站長(zhǎng) polarisxu
自己的原創(chuàng)文章
不限于 Go 技術(shù)
職場(chǎng)和創(chuàng)業(yè)經(jīng)驗(yàn)
Go語(yǔ)言中文網(wǎng)
每天為你
分享 Go 知識(shí)
Go愛(ài)好者值得關(guān)注
