Session
简介
在上一篇文章中介绍了Cookie的内容。在HTTP Request中,可以在Header中携带Cookie给服务端;在HTTP Response中,可以在Header中携带Cookie返回给客户端。但是,Cookie的结构体一般是固定的,携带的信息有限。此时,我们可以在服务端保存客户端的相关信息,然后客户端请求时,只需要携带一个Id给服务端,服务端根据此Id查询客户端相关的信息,这就是Session的基本机制。
这里列出了Session与Cookie的几个区别:
Cookie是通过HTTP协议的请求头中的
Cookie
字段与响应头中的Set-Cookie
字段进行传输的Cookie的结构体是固定的,所携带的信息有限
Cookie由服务端生成,返回给客户端,客户端请求时,再携带给服务端。所以,Cookie是一种将状态信息存储在客户端的机制。
Session机制是将状态信息存储在服务端,然后通过Cookie把SessionId传回给客户端
Session的结构是不固定的,用户可以自已定义,存储的信息量比Cookie要多
Session的后端存储引擎也比较丰富,有memory、file、redis、mysql等。
示例
接下来,我们通过一个例子(go语言)来展示一下session的使用。解释一下这段代码的意思:
在浏览器(客户端)上访问
x.x.x.x:8082/login?username=xxx
时,程序(服务端)会新建一个Session,记录登录的用户名,并把SessionId通过Cookie传回给浏览器在浏览器上访问
x.x.x.x:8082/whoami
时,浏览器会携带包含SessionId的Cookie给服务端,服务端根据SessionId查询到Session对象,得到用户名,返回给浏览器在浏览器上访问
x.x.x.x:8082/logout
时,浏览器会携带包含SessionId的Cookie给服务端,服务端会根据SeesionId删除对应的Session对象,并且告诉浏览器删除对应的Cookie
session.go
package main
import (
"net/http"
"github.com/astaxie/beego/session"
)
var globalSessions *session.Manager
func init() {
sessionConfig := &session.ManagerConfig{
CookieName: "gosessionid",
EnableSetCookie: true,
Gclifetime: 3600,
Maxlifetime: 3600,
Secure: false,
CookieLifeTime: 0,
ProviderConfig: "./tmp",
}
globalSessions, _ = session.NewManager("memory", sessionConfig)
go globalSessions.GC()
}
func main() {
http.HandleFunc("/login", Login)
http.HandleFunc("/logout", Logout)
http.HandleFunc("/whoami", WhoAmI)
http.ListenAndServe(":8082", nil)
}
func Login(w http.ResponseWriter, r *http.Request) {
sess, _ := globalSessions.SessionStart(w, r) // get or generate a Store object, sess is type of Store
username := sess.Get("username") // username is type of interface{}
if username != nil {
usernameInString, _ := username.(string) // convert interface{} to string
w.Write([]byte("already logged in as user : " + usernameInString))
} else {
queryUsername := r.URL.Query().Get("username")
if queryUsername == "" {
w.Write([]byte("query parameter missed : username"))
globalSessions.SessionDestroy(w, r)
return
}
sess.Set("username", queryUsername)
w.Write([]byte("logged in successfully as user : " + queryUsername))
}
}
func Logout(w http.ResponseWriter, r *http.Request) {
sess, _ := globalSessions.SessionStart(w, r) // get session object from request
username := sess.Get("username")
if username == nil {
w.Write([]byte("logout failed : no user logged in"))
}
globalSessions.SessionDestroy(w, r)
usernameInString, _ := username.(string)
w.Write([]byte("logout successfully : " + usernameInString))
}
func WhoAmI(w http.ResponseWriter, r *http.Request) {
sess, _ := globalSessions.SessionStart(w, r) // get session object from request
username := sess.Get("username")
if username == nil {
w.Write([]byte("i don't know who you are : no user logged in"))
globalSessions.SessionDestroy(w, r)
} else {
usernameInString, _ := username.(string)
w.Write([]byte("You are : " + usernameInString))
}
}
实验效果
首先登录
首次访问/login?username=peng,服务端会返回一个Cookie给浏览器,包含了SessionId的内容

携带上述的Cookie访问
接着,访问页面 /whoami,此时浏览器会携带Cookie给服务端,服务端根据Cookie中的SessionId查到出对应的Session,然后返回用户名给浏览器

登出系统
访问/logout,浏览器把Cookie携带给服务端后,服务端会删除该SessionId的Session对象,并且告知浏览器出删除这个Cookie

再次访问 /whoami
登出系统后,再次访问/whoami,由于浏览器没有携带SessionId相关的Cookie,所以服务端会报不知道客户端是谁

代码详细解析
sess, _ := globalSessions.SessionStart(w, r)
该语句的意思是从HTTP的请求头中读取承载SessionId的Cookie,然后在服务端查找出对应的Session对象,并且将该Cookie继续保存在HTTP的响应头中(http.RespondWriter);如果请求头中并没有相应的Cookie,则新建一个Session对象,并且把SessionId保存在Cookie中然后放到HTTP的响应头中。
sess.Set("username", queryUsername)
globalSessions.SessionStart(w, r)
返回的Session对象的结构体与具体的后端存储有关,在上面的代码中我们使用的memory存储引擎。详细的类的定义见下面的内容
代码中各种结构体及函数的源码
func NewManager(...)
func NewManager(provideName string, cf *ManagerConfig) (*Manager, error)
Manager struct
type Manager struct {
provider Provider
config *ManagerConfig
}
// getSid retrieves session identifier from HTTP Request.
// First try to retrieve id by reading from cookie, session cookie name is configurable,
// if not exist, then retrieve id from querying parameters.
//
// error is not nil when there is anything wrong.
// sid is empty when need to generate a new session id
// otherwise return an valid session id.
func (manager *Manager) getSid(r *http.Request) (string, error)
// SessionStart generate or read the session id from http request.
// if session id exists, return SessionStore with this id.
func (manager *Manager) SessionStart(w http.ResponseWriter, r *http.Request) (session Store, err error)
// SessionDestroy Destroy session by its id in http request cookie
func (manager *Manager) SessionDestroy(w http.ResponseWriter, r *http.Request)
// GetSessionStore Get SessionStore by its id
func (manager *Manager) GetSessionStore(sid string) (sessions Store, err error)
// GC Start session gc process.
// it can do gc in times after gc lifetime.
func (manager *Manager) GC()
// SessionRegenerateID Regenerate a session id for this SessionStore who's id is saving in http request.
func (manager *Manager) SessionRegenerateID(w http.ResponseWriter, r *http.Request) (session Store)
// GetActiveSession Get all active sessions count number.
func (manager *Manager) GetActiveSession() int
// Set cookie with https
func (manager *Manager) SetSecure(req *http.Request) bool
// inner function
func (manager *Manager) sessionID() (string, error)
// inner function
func (manager *Manager) isSecure(req *http.Request) bool
Store interface
// Store contains all data for one session process with specific id.
type Store interface {
Set(key, value interface{}) error //set session value
Get(key interface{}) interface{} //get session value
Delete(key interface{}) error //delete session value
SessionID() string //back current sessionID
SessionRelease(w http.ResponseWriter) // release the resource & save data to provider & return the data
Flush() error //delete all data
}
MemSessionStore struct
type MemSessionStore struct {
sid string //session id
timeAccessed time.Time //last access time
value map[interface{}]interface{} //session store
lock sync.RWMutex
}
// Set value to memory session
func (st *MemSessionStore) Set(key, value interface{}) error
// Get value from memory session by key
func (st *MemSessionStore) Get(key interface{}) interface{}
// Delete in memory session by key
func (st *MemSessionStore) Delete(key interface{}) error
// Flush clear all values in memory session
func (st *MemSessionStore) Flush() error
// SessionID get this id of memory session store
func (st *MemSessionStore) SessionID() string
// SessionRelease Implement method, no used.
func (st *MemSessionStore) SessionRelease(w http.ResponseWriter)
参考
Last updated
Was this helpful?