140 lines
3.6 KiB
Markdown
140 lines
3.6 KiB
Markdown
# 6.3 session儲存
|
||
上一節我們介紹了Session管理器的實現原理,定義了儲存session的介面,這小節我們將示例一個基於記憶體的session儲存介面的實現,其他的儲存方式,讀者可以自行參考示例來實現,記憶體的實現請看下面的例子程式碼
|
||
```Go
|
||
|
||
package memory
|
||
|
||
import (
|
||
"container/list"
|
||
"github.com/astaxie/session"
|
||
"sync"
|
||
"time"
|
||
)
|
||
|
||
var pder = &Provider{list: list.New()}
|
||
|
||
type SessionStore struct {
|
||
sid string //session id唯一標示
|
||
timeAccessed time.Time //最後訪問時間
|
||
value map[interface{}]interface{} //session裡面儲存的值
|
||
}
|
||
|
||
func (st *SessionStore) Set(key, value interface{}) error {
|
||
st.value[key] = value
|
||
pder.SessionUpdate(st.sid)
|
||
return nil
|
||
}
|
||
|
||
func (st *SessionStore) Get(key interface{}) interface{} {
|
||
pder.SessionUpdate(st.sid)
|
||
if v, ok := st.value[key]; ok {
|
||
return v
|
||
} else {
|
||
return nil
|
||
}
|
||
}
|
||
|
||
func (st *SessionStore) Delete(key interface{}) error {
|
||
delete(st.value, key)
|
||
pder.SessionUpdate(st.sid)
|
||
return nil
|
||
}
|
||
|
||
func (st *SessionStore) SessionID() string {
|
||
return st.sid
|
||
}
|
||
|
||
type Provider struct {
|
||
lock sync.Mutex //用來鎖
|
||
sessions map[string]*list.Element //用來儲存在記憶體
|
||
list *list.List //用來做gc
|
||
}
|
||
|
||
func (pder *Provider) SessionInit(sid string) (session.Session, error) {
|
||
pder.lock.Lock()
|
||
defer pder.lock.Unlock()
|
||
v := make(map[interface{}]interface{}, 0)
|
||
newsess := &SessionStore{sid: sid, timeAccessed: time.Now(), value: v}
|
||
element := pder.list.PushBack(newsess)
|
||
pder.sessions[sid] = element
|
||
return newsess, nil
|
||
}
|
||
|
||
func (pder *Provider) SessionRead(sid string) (session.Session, error) {
|
||
if element, ok := pder.sessions[sid]; ok {
|
||
return element.Value.(*SessionStore), nil
|
||
} else {
|
||
sess, err := pder.SessionInit(sid)
|
||
return sess, err
|
||
}
|
||
return nil, nil
|
||
}
|
||
|
||
func (pder *Provider) SessionDestroy(sid string) error {
|
||
if element, ok := pder.sessions[sid]; ok {
|
||
delete(pder.sessions, sid)
|
||
pder.list.Remove(element)
|
||
return nil
|
||
}
|
||
return nil
|
||
}
|
||
|
||
func (pder *Provider) SessionGC(maxlifetime int64) {
|
||
pder.lock.Lock()
|
||
defer pder.lock.Unlock()
|
||
|
||
for {
|
||
element := pder.list.Back()
|
||
if element == nil {
|
||
break
|
||
}
|
||
if (element.Value.(*SessionStore).timeAccessed.Unix() + maxlifetime) < time.Now().Unix() {
|
||
pder.list.Remove(element)
|
||
delete(pder.sessions, element.Value.(*SessionStore).sid)
|
||
} else {
|
||
break
|
||
}
|
||
}
|
||
}
|
||
|
||
func (pder *Provider) SessionUpdate(sid string) error {
|
||
pder.lock.Lock()
|
||
defer pder.lock.Unlock()
|
||
if element, ok := pder.sessions[sid]; ok {
|
||
element.Value.(*SessionStore).timeAccessed = time.Now()
|
||
pder.list.MoveToFront(element)
|
||
return nil
|
||
}
|
||
return nil
|
||
}
|
||
|
||
func init() {
|
||
pder.sessions = make(map[string]*list.Element, 0)
|
||
session.Register("memory", pder)
|
||
}
|
||
```
|
||
上面這個程式碼實現了一個記憶體儲存的session機制。透過init函式註冊到session管理器中。這樣就可以方便的呼叫了。我們如何來呼叫該引擎呢?請看下面的程式碼
|
||
```Go
|
||
|
||
import (
|
||
"github.com/astaxie/session"
|
||
_ "github.com/astaxie/session/providers/memory"
|
||
)
|
||
```
|
||
當import的時候已經執行了memory函式裡面的init函式,這樣就已經註冊到session管理器中,我們就可以使用了,透過如下方式就可以初始化一個session管理器:
|
||
```Go
|
||
|
||
var globalSessions *session.Manager
|
||
|
||
//然後在init函式中初始化
|
||
func init() {
|
||
globalSessions, _ = session.NewManager("memory", "gosessionid", 3600)
|
||
go globalSessions.GC()
|
||
}
|
||
|
||
```
|
||
## links
|
||
* [目錄](<preface.md>)
|
||
* 上一節: [Go如何使用session](<06.2.md>)
|
||
* 下一節: [預防session劫持](<06.4.md>)
|