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

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

然后在瀏覽器中就可以通過 http://localhost:8888/counter 訪問這個計(jì)數(shù)器了:

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

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

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

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

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