正在为Words Review 实现云端同步的功能,需要在服务器端维护在线用户的信息,这就需要session的管理。 Web.go 没有实现session模块, go dashboard 上有一个session的实现,但build状态是不通过,而且看源码实现的太复杂。
我没有去仔细翻看session的相关标准,只是基于我之前对web应用中cookie session的理解, 一个基本的session模块只需要能够针对每个session identifier正确的存取数据,管理生命周期就可以了。
下面是在golang中的简单实现, 你可以在github上找到源代码。
首先定义session实例的数据结构。 一个session对象就是一个字符串,存储这个session的id, 由于golang不允许对系统内置数据类型添加方法,我们需要一个自定义类型:
type Session string
出于基本的安全考虑,session id需要唯一, 不可预测。 GUID是个不错的选择, 下面这个函数用来产生session id。
golang还没有官方的windows支持,目前的go语言版本调用windows api好像还有问题, 而且我的site也不打算跑在windows下面。 所以windows下guid暂时先用时间戳加随机数的方式, linux下直接读取/dev/urandom:
func newGuid() (string, os.Error) {
if syscall.OS == "windows" {
//no /dev/urandom on windows
//TODO: use some windows api instead ?
guid := getMd5Hex(time.UTC().Format(time.ANSIC) + strconv.Itoa64(rand.Int63()))
return guid, nil
}
f, err := os.Open("/dev/urandom")
if err != nil {
return "", err
}
defer f.Close()
b := make([]byte, 16)
_, err = f.Read(b)
if err != nil {
return "", err
}
uuid := fmt.Sprintf("%x-%x-%x-%x-%x", b[0:4], b[4:6], b[6:8], b[8:10], b[10:])
return uuid, nil
}
生命周期的管理使用 goroutines 和 channels, 在指定时间后删除session:
func New() Session {
return NewTimeout(sessionTimeout)
}
func NewTimeout(timeout int64) Session {
sid, err := newGuid()
if err != nil {
panic(err)
}
sessions[sid] = make(map[string]interface{})
t := time.NewTimer(timeout * 1e9) //timer接受的是nanoseconds
go startSession(t.C, sid)
return Session(sid)
}
func startSession(c <-chan int64, sid string) {
<-c
sessions[sid] = nil, false
}
数据的存取就比较简单了,使用一个package level可见的map变量即可简单实现。
用法示例:
创建新的session:
s := session.New() //默认过期时间1小时
s := session.NewTimeout(20 * 60) // 20 分钟后过期
存取session数据:
err := s.Put("Username", "Bob")
err = s.Put("Logintime", time.UTC())
v, err := s.Get("Logintime") //return interface{}, need type assertion
loginTime := v.(*time.Time)
结合web.go:
s := session.New()
ctx.SetCookie("u", string(s), 3600) //set session-cookie
err := s.Put("user", u)
关于session肯定还有很多细节没有处理,但满足我现在的需求了。
Comments
That hits the target dead cneter! Great answer!
Leave a comment