go 實現session

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

文章轉自https://blog.csdn.net/lzy_zhi_yuan/article/details/73127601

go裡沒有官方的的session,所以才去封裝了session管理器,具體步驟見代碼注釋,將在後面的文章進行講解具體實戰。

//Session操作介面,不同儲存方式的Sesion操作不同,實現也不同type Session interface {    Set(key, value interface{})    Get(key interface{}) interface{}    Remove(key interface{}) error    GetId() string}//session實現type SessionFromMemory struct {    sid              string                      //唯一標示    lock             sync.Mutex                  //一把互斥鎖    lastAccessedTime time.Time                   //最後訪問時間    maxAge           int64                       //逾時時間    data             map[interface{}]interface{} //主要資料}//執行個體化func newSessionFromMemory() *SessionFromMemory {    return &SessionFromMemory{        data:   make(map[interface{}]interface{}),        maxAge: 60 * 30, //預設30分鐘    }}//同一個會話均可調用,進行設定,改操作必須擁有排斥鎖func (si *SessionFromMemory) Set(key, value interface{}) {    si.lock.Lock()    defer si.lock.Unlock()    si.data[key] = value}func (si *SessionFromMemory) Get(key interface{}) interface{} {    if value := si.data[key]; value != nil {        return value    }    return nil}func (si *SessionFromMemory) Remove(key interface{}) error {    if value := si.data[key]; value != nil {        delete(si.data, key)    }    return nil}func (si *SessionFromMemory) GetId() string {    return si.sid}//session儲存方式介面,可以儲存在記憶體,資料庫或者檔案//分別實現該介面即可//如存入資料庫的CRUD操作type Storage interface {    //初始化一個session,id根據需要產生後傳入    InitSession(sid string, maxAge int64) (Session, error)    //根據sid,獲得當前session    SetSession(session Session) error    //銷毀session    DestroySession(sid string) error    //回收    GCSession()}//session來自記憶體type FromMemory struct {    //由於session包含所有的請求    //並行時,保證資料獨立、一致、安全    lock     sync.Mutex //互斥鎖    sessions map[string]Session}//執行個體化一個記憶體實現func newFromMemory() *FromMemory {    return &FromMemory{        sessions: make(map[string]Session, 0),    }}//初始換會話session,這個結構體操作實現Session介面func (fm *FromMemory) InitSession(sid string, maxAge int64) (Session, error) {    fm.lock.Lock()    defer fm.lock.Unlock()    newSession := newSessionFromMemory()    newSession.sid = sid    if maxAge != 0 {        newSession.maxAge = maxAge    }    newSession.lastAccessedTime = time.Now()    fm.sessions[sid] = newSession //記憶體管理map    return newSession, nil}//設定func (fm *FromMemory) SetSession(session Session) error {    fm.sessions[session.GetId()] = session    return nil}//銷毀sessionfunc (fm *FromMemory) DestroySession(sid string) error {    if _, ok := fm.sessions[sid]; ok {        delete(fm.sessions, sid)        return nil    }    return nil}//監判逾時func (fm *FromMemory) GCSession() {    sessions := fm.sessions    //fmt.Println("gc session")    if len(sessions) < 1 {        return    }    //fmt.Println("current active sessions ", sessions)    for k, v := range sessions {        t := (v.(*SessionFromMemory).lastAccessedTime.Unix()) + (v.(*SessionFromMemory).maxAge)        if t < time.Now().Unix() { //逾時了            fmt.Println("timeout-------->", v)            delete(fm.sessions, k)        }    }}//--------------session_manager----------------------//管理Session,實際操作cookie,Storage//由於該結構體是整個應用層級的,寫、修改都需要枷鎖type SessionManager struct {    //session資料最終需要在用戶端(瀏覽器)和伺服器各存一份    //用戶端時,存放在cookie中    cookieName string    //存放方式,如記憶體,資料庫,檔案    storage Storage    //逾時時間    maxAge int64    //由於session包含所有的請求    //並行時,保證資料獨立、一致、安全    lock sync.Mutex}//執行個體化一個session管理器func NewSessionManager() *SessionManager {    sessionManager := &SessionManager{        cookieName: "lzy-cookie",        storage:    newFromMemory(), //預設以記憶體實現        maxAge:     60 * 30,         //預設30分鐘    }    go sessionManager.GC()    return sessionManager}func (m *SessionManager) GetCookieN() string {    return m.cookieName}//先判斷當前請求的cookie中是否存在有效session,存在返回,不存在建立func (m *SessionManager) BeginSession(w http.ResponseWriter, r *http.Request) Session {    //防止處理時,進入另外的請求    m.lock.Lock()    defer m.lock.Unlock()    cookie, err := r.Cookie(m.cookieName)    if err != nil || cookie.Value == "" { //如果當前請求沒有改cookie名字對應的cookie        fmt.Println("-----------> current session not exists")        //建立一個        sid := m.randomId()        //根據儲存session方式,如記憶體,資料庫中建立        session, _ := m.storage.InitSession(sid, m.maxAge) //該方法有自己的鎖,多處調用到        maxAge := m.maxAge        if maxAge == 0 {            maxAge = session.(*SessionFromMemory).maxAge        }        //用session的ID於cookie關聯        //cookie名字和失效時間由session管理器維護        cookie := http.Cookie{            Name: m.cookieName,            //這裡是並發不安全的,但是這個方法已上鎖            Value:    url.QueryEscape(sid), //轉義特殊符號@#¥%+*-等            Path:     "/",            HttpOnly: true,            MaxAge:   int(maxAge),            Expires:  time.Now().Add(time.Duration(maxAge)),        }        http.SetCookie(w, &cookie) //設定到響應中        return session    } else { //如果存在        sid, _ := url.QueryUnescape(cookie.Value)        //反轉義特殊符號        session := m.storage.(*FromMemory).sessions[sid] //從儲存session介質中擷取        fmt.Println("session --------->", session)        if session == nil {            fmt.Println("-----------> current session is nil")            //建立一個            //sid := m.randomId()            //根據儲存session方式,如記憶體,資料庫中建立            newSession, _ := m.storage.InitSession(sid, m.maxAge) //該方法有自己的鎖,多處調用到            maxAge := m.maxAge            if maxAge == 0 {                maxAge = newSession.(*SessionFromMemory).maxAge            }            //用session的ID於cookie關聯            //cookie名字和失效時間由session管理器維護            newCookie := http.Cookie{                Name: m.cookieName,                //這裡是並發不安全的,但是這個方法已上鎖                Value:    url.QueryEscape(sid), //轉義特殊符號@#¥%+*-等                Path:     "/",                HttpOnly: true,                MaxAge:   int(maxAge),                Expires:  time.Now().Add(time.Duration(maxAge)),            }            http.SetCookie(w, &newCookie) //設定到響應中            return newSession        }        fmt.Println("-----------> current session exists")        return session    }}//更新逾時func (m *SessionManager) Update(w http.ResponseWriter, r *http.Request) {    m.lock.Lock()    defer m.lock.Unlock()    cookie, err := r.Cookie(m.cookieName)    if err != nil {        return    }    t := time.Now()    sid, _ := url.QueryUnescape(cookie.Value)    sessions := m.storage.(*FromMemory).sessions    session := sessions[sid].(*SessionFromMemory)    session.lastAccessedTime = t    sessions[sid] = session    if m.maxAge != 0 {        cookie.MaxAge = int(m.maxAge)    } else {        cookie.MaxAge = int(session.maxAge)    }    http.SetCookie(w, cookie)}//通過ID擷取sessionfunc (m *SessionManager) GetSessionById(sid string) Session {    session := m.storage.(*FromMemory).sessions[sid]    return session}//是否記憶體中存在func (m *SessionManager) MemoryIsExists(sid string) bool {    _, ok := m.storage.(*FromMemory).sessions[sid]    if ok {        return true    }    return false}//手動銷毀session,同時刪除cookiefunc (m *SessionManager) Destroy(w http.ResponseWriter, r *http.Request) {    cookie, err := r.Cookie(m.cookieName)    if err != nil || cookie.Value == "" {        return    } else {        m.lock.Lock()        defer m.lock.Unlock()        sid, _ := url.QueryUnescape(cookie.Value)        m.storage.DestroySession(sid)        cookie2 := http.Cookie{            MaxAge:  0,            Name:    m.cookieName,            Value:   "",            Path:    "/",            Expires: time.Now().Add(time.Duration(0)),        }        http.SetCookie(w, &cookie2)    }}func (m *SessionManager) CookieIsExists(r *http.Request) bool {    _, err := r.Cookie(m.cookieName)    if err != nil {        return false    }    return true}//開啟每個會話,同時定時調用該方法//到達session最大生命時,且逾時時。回收它func (m *SessionManager) GC() {    m.lock.Lock()    defer m.lock.Unlock()    m.storage.GCSession()    //在多長時間後執行匿名函數,這裡指在某個時間後執行GC    time.AfterFunc(time.Duration(m.maxAge*10), func() {        m.GC()    })}//是否將session放入記憶體(操作記憶體)預設是操作記憶體func (m *SessionManager) IsFromMemory() {    m.storage = newFromMemory()}//是否將session放入資料庫(操作資料庫)func (m *SessionManager) IsFromDB() {    //TODO    //關於存資料庫暫未實現}func (m *SessionManager) SetMaxAge(t int64) {    m.maxAge = t}//如果你自己實現儲存session的方式,可以調該函數進行定義func (m *SessionManager) SetSessionFrom(storage Storage) {    m.storage = storage}//產生一定長度的隨機數func (m *SessionManager) randomId() string {    b := make([]byte, 32)    if _, err := io.ReadFull(rand.Reader, b); err != nil {        return ""    }    //加密    return base64.URLEncoding.EncodeToString(b)

以上封裝的方法還有類似的 具體參考https://www.cnblogs.com/chevin/p/5669940.html

540 次點擊  ∙  1 贊  
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.