From bd4d273e1c44499ca4f3984779f84ed3901c5198 Mon Sep 17 00:00:00 2001 From: John Date: Sun, 28 Jul 2019 11:50:12 +0800 Subject: [PATCH] improve ghttp for session --- g/net/ghttp/ghttp_server_config.go | 7 +- g/net/ghttp/ghttp_server_session.go | 66 ++++++++++++++-- g/util/gconv/gconv_slice.go | 20 ++--- geg/net/ghttp/server/session/config.toml | 2 + geg/net/ghttp/server/session/session.go | 2 +- geg/net/ghttp/server/session/session_redis.go | 78 +++++++++++++++++++ 6 files changed, 155 insertions(+), 20 deletions(-) create mode 100644 geg/net/ghttp/server/session/config.toml create mode 100644 geg/net/ghttp/server/session/session_redis.go diff --git a/g/net/ghttp/ghttp_server_config.go b/g/net/ghttp/ghttp_server_config.go index 0a5b31e90..cb8fee3b5 100644 --- a/g/net/ghttp/ghttp_server_config.go +++ b/g/net/ghttp/ghttp_server_config.go @@ -9,11 +9,12 @@ package ghttp import ( "crypto/tls" "fmt" - "github.com/gogf/gf/g/os/gfile" - "github.com/gogf/gf/g/os/glog" "net/http" "strconv" "time" + + "github.com/gogf/gf/g/os/gfile" + "github.com/gogf/gf/g/os/glog" ) const ( @@ -25,7 +26,7 @@ const ( NAME_TO_URI_TYPE_CAMEL = 3 // 采用驼峰命名方式 gDEFAULT_COOKIE_PATH = "/" // 默认path gDEFAULT_COOKIE_MAX_AGE = 86400 * 365 // 默认cookie有效期(一年) - gDEFAULT_SESSION_MAX_AGE = 600000 // 默认session有效期(600秒) + gDEFAULT_SESSION_MAX_AGE = 86400 // 默认session有效期(一天) gDEFAULT_SESSION_ID_NAME = "gfsessionid" // 默认存放Cookie中的SessionId名称 gCHANGE_CONFIG_WHILE_RUNNING_ERROR = "cannot be changed while running" ) diff --git a/g/net/ghttp/ghttp_server_session.go b/g/net/ghttp/ghttp_server_session.go index 01fc03dd5..6a2411ae0 100644 --- a/g/net/ghttp/ghttp_server_session.go +++ b/g/net/ghttp/ghttp_server_session.go @@ -8,14 +8,16 @@ package ghttp import ( + "encoding/json" + "strconv" + "strings" + "time" + "github.com/gogf/gf/g/container/gmap" "github.com/gogf/gf/g/container/gvar" "github.com/gogf/gf/g/os/gtime" "github.com/gogf/gf/g/util/gconv" "github.com/gogf/gf/g/util/grand" - "strconv" - "strings" - "time" ) // SESSION对象 @@ -62,13 +64,18 @@ func (s *Session) init() { } } +// MarshalJSON implements the interface MarshalJSON for json.Marshal. +func (s *Session) MarshalJSON() ([]byte, error) { + return json.Marshal(s.data) +} + // 获取/创建SessionId func (s *Session) Id() string { s.init() return s.id } -// 获取当前session所有数据 +// 获取当前session所有数据,注意是值拷贝 func (s *Session) Map() map[string]interface{} { if len(s.id) > 0 || s.request.Cookie.GetSessionId() != "" { s.init() @@ -77,6 +84,15 @@ func (s *Session) Map() map[string]interface{} { return nil } +// 获得session map大小 +func (s *Session) Size() int { + if len(s.id) > 0 || s.request.Cookie.GetSessionId() != "" { + s.init() + return s.data.Size() + } + return 0 +} + // 设置session func (s *Session) Set(key string, value interface{}) { s.init() @@ -117,7 +133,7 @@ func (s *Session) GetVar(key string, def ...interface{}) *gvar.Var { return gvar.New(s.Get(key, def...), true) } -// 删除session +// 删除指定session键值对 func (s *Session) Remove(key string) { if len(s.id) > 0 || s.request.Cookie.GetSessionId() != "" { s.init() @@ -125,6 +141,17 @@ func (s *Session) Remove(key string) { } } +// 从json字符串中恢复session数据 +func (s *Session) RestoreFromJson(data []byte) (err error) { + if len(s.id) > 0 || s.request.Cookie.GetSessionId() != "" { + s.init() + s.data.LockFunc(func(m map[string]interface{}) { + err = json.Unmarshal(data, &m) + }) + } + return +} + // 清空session func (s *Session) Clear() { if len(s.id) > 0 || s.request.Cookie.GetSessionId() != "" { @@ -228,7 +255,34 @@ func (s *Session) GetDuration(key string, def ...interface{}) time.Duration { return gconv.Duration(s.Get(key, def...)) } -// 将变量转换为对象,注意 pointer 参数必须为struct指针 +func (s *Session) GetMap(value interface{}, tags ...string) map[string]interface{} { + return gconv.Map(value, tags...) +} + +func (s *Session) GetMapDeep(value interface{}, tags ...string) map[string]interface{} { + return gconv.MapDeep(value, tags...) +} + +func (s *Session) GetMaps(value interface{}, tags ...string) []map[string]interface{} { + return gconv.Maps(value, tags...) +} + +func (s *Session) GetMapsDeep(value interface{}, tags ...string) []map[string]interface{} { + return gconv.MapsDeep(value, tags...) +} + func (s *Session) GetStruct(key string, pointer interface{}, mapping ...map[string]string) error { return gconv.Struct(s.Get(key), pointer, mapping...) } + +func (s *Session) GetStructDeep(key string, pointer interface{}, mapping ...map[string]string) error { + return gconv.StructDeep(s.Get(key), pointer, mapping...) +} + +func (s *Session) GetStructs(key string, pointer interface{}, mapping ...map[string]string) error { + return gconv.Structs(s.Get(key), pointer, mapping...) +} + +func (s *Session) GetStructsDeep(key string, pointer interface{}, mapping ...map[string]string) error { + return gconv.StructsDeep(s.Get(key), pointer, mapping...) +} diff --git a/g/util/gconv/gconv_slice.go b/g/util/gconv/gconv_slice.go index 0592e5362..137754333 100644 --- a/g/util/gconv/gconv_slice.go +++ b/g/util/gconv/gconv_slice.go @@ -379,40 +379,40 @@ func Interfaces(i interface{}) []interface{} { } // Maps converts to []map[string]interface{}. -func Maps(i interface{}) []map[string]interface{} { - if i == nil { +func Maps(value interface{}, tags ...string) []map[string]interface{} { + if value == nil { return nil } - if r, ok := i.([]map[string]interface{}); ok { + if r, ok := value.([]map[string]interface{}); ok { return r } else { - array := Interfaces(i) + array := Interfaces(value) if len(array) == 0 { return nil } list := make([]map[string]interface{}, len(array)) for k, v := range array { - list[k] = Map(v) + list[k] = Map(v, tags...) } return list } } // MapsDeep converts to []map[string]interface{} recursively. -func MapsDeep(i interface{}) []map[string]interface{} { - if i == nil { +func MapsDeep(value interface{}, tags ...string) []map[string]interface{} { + if value == nil { return nil } - if r, ok := i.([]map[string]interface{}); ok { + if r, ok := value.([]map[string]interface{}); ok { return r } else { - array := Interfaces(i) + array := Interfaces(value) if len(array) == 0 { return nil } list := make([]map[string]interface{}, len(array)) for k, v := range array { - list[k] = MapDeep(v) + list[k] = MapDeep(v, tags...) } return list } diff --git a/geg/net/ghttp/server/session/config.toml b/geg/net/ghttp/server/session/config.toml new file mode 100644 index 000000000..d5195ad6d --- /dev/null +++ b/geg/net/ghttp/server/session/config.toml @@ -0,0 +1,2 @@ +[redis] + default = "127.0.0.1:6379,10" \ No newline at end of file diff --git a/geg/net/ghttp/server/session/session.go b/geg/net/ghttp/server/session/session.go index b7893bd56..3d901fdd3 100644 --- a/geg/net/ghttp/server/session/session.go +++ b/geg/net/ghttp/server/session/session.go @@ -22,7 +22,7 @@ func (c *Controller) DoLogin() { } func (c *Controller) Main() { - c.Response.WriteJson(c.Session.Data()) + c.Response.WriteJson(c.Session.Map()) } func main() { diff --git a/geg/net/ghttp/server/session/session_redis.go b/geg/net/ghttp/server/session/session_redis.go new file mode 100644 index 000000000..525f43b8e --- /dev/null +++ b/geg/net/ghttp/server/session/session_redis.go @@ -0,0 +1,78 @@ +package main + +import ( + "encoding/json" + + "github.com/gogf/gf/g" + "github.com/gogf/gf/g/net/ghttp" + "github.com/gogf/gf/g/os/gtime" +) + +// 测试,SESSION写入 +func SessionSet(r *ghttp.Request) { + r.Session.Set("time", gtime.Second()) + r.Response.WriteJson("ok") +} + +// 测试,SESSION读取 +func SessionGet(r *ghttp.Request) { + r.Response.WriteJson(r.Session.Map()) +} + +// 请求处理之前将Redis中的数据读取出来并存储到SESSION对象中。 +func RedisHandlerGet(r *ghttp.Request) { + if !r.IsFileRequest() { + sessionId := r.Cookie.GetSessionId() + if sessionId == "" { + return + } + value, err := g.Redis().DoVar("GET", sessionId) + if err != nil { + panic(err) + } + if !value.IsNil() { + err := r.Session.RestoreFromJson(value.Bytes()) + if err != nil { + panic(err) + } + } + } +} + +// 请求结束时将SESSION数据存储到Redis中,或者在SESSION删除时也删除Redis中的数据。 +func RedisHandlerSet(r *ghttp.Request) { + if !r.IsFileRequest() { + sessionId := r.Cookie.GetSessionId() + if sessionId == "" { + return + } + err := (error)(nil) + if r.Session.Size() > 0 { + value, err := json.Marshal(r.Session) + if err != nil { + panic(err) + } + _, err = g.Redis().Do("SETEX", r.Cookie.GetSessionId(), r.Server.GetSessionMaxAge(), value) + if err != nil { + panic(err) + } + } else { + _, err = g.Redis().Do("DEL", r.Cookie.GetSessionId()) + if err != nil { + panic(err) + } + } + } +} + +func main() { + s := g.Server() + s.BindHandler("/set", SessionSet) + s.BindHandler("/get", SessionGet) + s.BindHookHandlerByMap("/*", map[string]ghttp.HandlerFunc{ + ghttp.HOOK_BEFORE_SERVE: RedisHandlerGet, + ghttp.HOOK_AFTER_SERVE: RedisHandlerSet, + }) + s.SetPort(8199) + s.Run() +}