cookie,session解耦

This commit is contained in:
John
2017-12-31 12:15:04 +08:00
parent 31727437fa
commit fd99670d55
10 changed files with 125 additions and 123 deletions

View File

@ -9,7 +9,6 @@ package gmvc
import (
"gitee.com/johng/gf/g/net/ghttp"
"gitee.com/johng/gf/g/net/gsession"
)
// 控制器基类
@ -18,7 +17,7 @@ type Controller struct {
Request *ghttp.ClientRequest // 请求数据对象
Response *ghttp.ServerResponse // 返回数据对象
Cookie *ghttp.Cookie // COOKIE操作对象
Session *gsession.Session // SESSION操作对象
Session *ghttp.Session // SESSION操作对象
View *View // 视图对象
}
@ -27,9 +26,9 @@ func (c *Controller) Init(s *ghttp.Server, r *ghttp.ClientRequest, w *ghttp.Serv
c.Server = s
c.Request = r
c.Response = w
c.Cookie = ghttp.NewCookie(c.Request, c.Response)
c.View = NewView(c)
c.Session = gsession.Get(c.Cookie.SessionId())
c.View = NewView(w)
c.Cookie = r.Cookie
c.Session = r.Session
}
// 控制器结束请求接口方法

View File

@ -11,22 +11,23 @@ import (
"html/template"
"gitee.com/johng/gf/g/os/gview"
"gitee.com/johng/gf/g/frame/gins"
"gitee.com/johng/gf/g/net/ghttp"
)
// 视图对象(一个请求一个视图对象,用完即销毁)
type View struct {
mu sync.RWMutex // 并发互斥锁
ctl *Controller // 所属控制器
view *gview.View // 底层视图对象
data map[string]interface{} // 视图数据
mu sync.RWMutex // 并发互斥锁
view *gview.View // 底层视图对象
data map[string]interface{} // 视图数据
response *ghttp.ServerResponse // 数据返回对象
}
// 创建一个MVC请求中使用的视图对象
func NewView(c *Controller) *View {
func NewView(w *ghttp.ServerResponse) *View {
return &View{
ctl : c,
view : gins.View(),
data : make(map[string]interface{}),
view : gins.View(),
data : make(map[string]interface{}),
response : w,
}
}
@ -69,10 +70,10 @@ func (view *View) Display(files...string) error {
file = files[0]
}
if content, err := view.Parse(file); err != nil {
view.ctl.Response.WriteString("Tpl Parsing Error: " + err.Error())
view.response.WriteString("Tpl Parsing Error: " + err.Error())
return err
} else {
view.ctl.Response.Write(content)
view.response.Write(content)
}
return nil
}

View File

@ -9,7 +9,6 @@ import (
"net/http"
"strings"
"time"
"net/url"
"bytes"
)
@ -18,13 +17,6 @@ type Client struct {
http.Client
}
// 请求对象
type ClientRequest struct {
http.Request
id uint64 // 请求id(唯一)
getvals *url.Values // GET参数
}
// 客户端请求结果对象
type ClientResponse struct {
http.Response

View File

@ -7,13 +7,19 @@ package ghttp
import (
"io/ioutil"
"gitee.com/johng/gf/g/encoding/gjson"
"net/http"
"net/url"
"gitee.com/johng/gf/g/util/gconv"
"gitee.com/johng/gf/g/encoding/gjson"
)
// 获取当前请求的id
func (r *ClientRequest) Id() uint64 {
return r.id
// 请求对象
type ClientRequest struct {
http.Request
getvals *url.Values // GET参数
Id uint64 // 请求id(唯一)
Cookie *Cookie // 与当前请求绑定的Cookie对象(并发安全)
Session *Session // 与当前请求绑定的Session对象(并发安全)
}
// 获得指定名称的get参数列表

View File

@ -45,7 +45,7 @@ var cookies = gmap.NewUintInterfaceMap()
// 创建一个cookie对象与传入的请求对应
func NewCookie(r *ClientRequest, w *ServerResponse) *Cookie {
if r := GetCookie(r.Id()); r != nil {
if r := GetCookie(r.Id); r != nil {
return r
}
c := &Cookie {
@ -55,7 +55,7 @@ func NewCookie(r *ClientRequest, w *ServerResponse) *Cookie {
response : w,
}
c.init()
cookies.Set(uint(r.Id()), c)
cookies.Set(uint(r.Id), c)
return c
}
@ -67,11 +67,6 @@ func GetCookie(requestid uint64) *Cookie {
return nil
}
// 请求完毕后删除已经存在的Cookie对象
func RemoveCookie(requestid uint64) {
cookies.Remove(uint(requestid))
}
// 获取默认的domain参数
func defaultDomain(r *ClientRequest) string {
return strings.Split(r.Host, ":")[0]
@ -90,7 +85,12 @@ func (c *Cookie) init() {
// 获取SessionId
func (c *Cookie) SessionId() string {
return c.Get(SESSION_ID_NAME)
v := c.Get(SESSION_ID_NAME)
if v == "" {
v = makeSessionId()
c.SetSessionId(v)
}
return v
}
// 设置SessionId
@ -132,6 +132,11 @@ func (c *Cookie) Remove(key, domain, path string) {
c.SetCookie(key, "", domain, path, -86400)
}
// 请求完毕后删除已经存在的Cookie对象
func (c *Cookie) Close() {
cookies.Remove(uint(c.request.Id))
}
// 输出到客户端
func (c *Cookie) Output() {
c.mu.RLock()

View File

@ -16,7 +16,6 @@ import (
"net/http"
"path/filepath"
"gitee.com/johng/gf/g/os/gfile"
"gitee.com/johng/gf/g/net/gsession"
"gitee.com/johng/gf/g/encoding/ghtml"
)
@ -39,7 +38,7 @@ func (s *Server)handleRequest(w http.ResponseWriter, r *http.Request) {
// 构造请求/返回参数对象
request := &ClientRequest{}
response := &ServerResponse{}
request.id = s.increServed()
request.Id = s.increServed()
request.Request = *r
response.ResponseWriter = w
if h := s.getHandler(gDEFAULT_DOMAIN, r.Method, r.URL.Path); h != nil {
@ -55,13 +54,10 @@ func (s *Server)handleRequest(w http.ResponseWriter, r *http.Request) {
// 初始化控制器
func (s *Server)callHandler(h *HandlerItem, r *ClientRequest, w *ServerResponse) {
// 会话处理每个请求必定有一个sessionid
cookie := NewCookie(r, w)
sessionid := cookie.SessionId()
if sessionid == "" {
sessionid = gsession.Id()
cookie.SetSessionId(sessionid)
}
// 会话处理
r.Cookie = NewCookie(r, w)
r.Session = GetSession(r.Cookie.SessionId())
// 请求处理
if h.faddr == nil {
// 新建一个控制器对象处理请求
@ -80,13 +76,15 @@ func (s *Server)callHandler(h *HandlerItem, r *ClientRequest, w *ServerResponse)
}
// 输出Cookie
cookie.Output()
r.Cookie.Output()
// 输出缓冲区
w.OutputBuffer()
// 删除当前会话的Cookie
RemoveCookie(r.Id())
// 关闭当前会话的Cookie
go r.Cookie.Close()
// 更新Sssion会话超时时间
go r.Session.UpdateExpire()
}
// 处理静态文件请求

View File

@ -3,8 +3,8 @@
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://gitee.com/johng/gf.
package gsession
// 并发安全的Session管理器
package ghttp
import (
"sync"
@ -14,10 +14,8 @@ import (
"gitee.com/johng/gf/g/os/gcache"
"gitee.com/johng/gf/g/util/grand"
"gitee.com/johng/gf/g/container/gmap"
)
const (
DEFAULT_EXPIRE_TIME = 600 // 默认过期间隔(10分钟)
"gitee.com/johng/gf/g/util/gconv"
"sync/atomic"
)
// 单个session对象
@ -25,114 +23,93 @@ type Session struct {
mu sync.RWMutex // 并发安全互斥锁
id string // sessionid
data *gmap.StringInterfaceMap // session数据
expire int // 过期间隔(秒)
}
// 默认session过期时间(秒)
var defaultSessionMaxAge int32 = 600
// 生成一个唯一的sessionid字符串
func Id() string {
func makeSessionId() string {
return strings.ToUpper(strconv.FormatInt(gtime.Nanosecond(), 32) + grand.RandStr(3))
}
// 设置默认的session过期时间
func SetSessionMaxAge(maxage int) {
atomic.StoreInt32(&defaultSessionMaxAge, int32(maxage))
}
// 获取或者生成一个session对象
func Get(sessionid string) *Session {
if r := gcache.Get(cacheKey(sessionid)); r != nil {
func GetSession(sessionid string) *Session {
if r := gcache.Get(sessionCacheKey(sessionid)); r != nil {
return r.(*Session)
}
s := &Session {
id : sessionid,
data : gmap.NewStringInterfaceMap(),
expire : DEFAULT_EXPIRE_TIME,
}
s.updateExpire()
return s
}
// session在gache中的缓存键名
func cacheKey(sessionid string) string {
func sessionCacheKey(sessionid string) string {
return "session_" + sessionid
}
// 获取sessionid
func (s *Session) Id () string {
go s.updateExpire()
func (s *Session) Id() string {
return s.id
}
// 获取当前session所有数据
func (s *Session) Data () map[string]interface{} {
go s.updateExpire()
return *s.data.Clone()
}
// 设置session过期间隔(秒)
func (s *Session) SetExpire (expire int) {
s.mu.Lock()
defer s.mu.Unlock()
go s.updateExpire()
s.expire = expire
}
// 设置session
func (s *Session) Set (k string, v interface{}) {
go s.updateExpire()
s.data.Set(k, v)
}
// 批量设置
func (s *Session) BatchSet (m map[string]interface{}) {
s.data.BatchSet(m)
}
// 获取session
func (s *Session) Get (k string) interface{} {
go s.updateExpire()
return s.data.Get(k)
}
func (s *Session) GetString (k string) string {
return gconv.String(s.Get(k))
}
func (s *Session) GetBool (k string) bool {
return gconv.Bool(s.Get(k))
}
func (s *Session) GetInt (k string) int {
go s.updateExpire()
if r := s.data.Get(k); r != nil {
return r.(int)
}
return 0
return gconv.Int(s.Get(k))
}
func (s *Session) GetUint (k string) uint {
go s.updateExpire()
if r := s.data.Get(k); r != nil {
return r.(uint)
}
return 0
return gconv.Uint(s.Get(k))
}
func (s *Session) GetFloat32 (k string) float32 {
go s.updateExpire()
if r := s.data.Get(k); r != nil {
return r.(float32)
}
return 0
return gconv.Float32(s.Get(k))
}
func (s *Session) GetFloat64 (k string) float64 {
go s.updateExpire()
if r := s.data.Get(k); r != nil {
return r.(float64)
}
return 0
}
// 获取session(字符串)
func (s *Session) GetString (k string) string {
go s.updateExpire()
if r := s.data.Get(k); r != nil {
return r.(string)
}
return ""
return gconv.Float64(s.Get(k))
}
// 删除session
func (s *Session) Remove (k string) {
go s.updateExpire()
s.data.Remove(k)
}
// 更新过期时间
func (s *Session) updateExpire() {
//gcache.Set(cacheKey(s.id), s, int64(s.expire*1000))
gcache.Set(cacheKey(s.id), s, 0)
}
// 更新过期时间(如果用在守护进程中长期使用,需要手动调用进行更新,防止超时被清除)
func (s *Session) UpdateExpire() {
gcache.Set(sessionCacheKey(s.id), s, int64(defaultSessionMaxAge*1000))
}

View File

@ -0,0 +1,19 @@
package demo
import (
"gitee.com/johng/gf/g/os/gtime"
"gitee.com/johng/gf/g/net/ghttp"
)
func init() {
ghttp.GetServer().BindHandler("/cookie", Cookie)
}
// 用于函数映射
func Cookie(s *ghttp.Server, r *ghttp.ClientRequest, w *ghttp.ServerResponse) {
datetime := r.Cookie.Get("datetime")
r.Cookie.Set("datetime", gtime.Datetime())
w.WriteString("datetime:" + datetime)
}

View File

@ -2,8 +2,6 @@ package demo
import (
"gitee.com/johng/gf/g/net/ghttp"
"gitee.com/johng/gf/g/net/gsession"
"strconv"
)
@ -15,17 +13,5 @@ func init() {
// 用于函数映射
func Hello(s *ghttp.Server, r *ghttp.ClientRequest, w *ghttp.ServerResponse) {
cookie := ghttp.GetCookie(r.Id())
session := gsession.Get(cookie.SessionId())
id := 0
for i := 0; i < 1; i++ {
if r := session.Get("id"); r != nil {
id = r.(int)
}
id++
session.Set("id", id)
}
w.WriteString("Hello World!" + strconv.Itoa(id))
w.WriteString("Hello World!")
}

View File

@ -0,0 +1,19 @@
package demo
import (
"gitee.com/johng/gf/g/net/ghttp"
"strconv"
)
func init() {
ghttp.GetServer().BindHandler("/session", Session)
}
// 用于函数映射
func Session(s *ghttp.Server, r *ghttp.ClientRequest, w *ghttp.ServerResponse) {
id := r.Session.GetInt("id")
r.Session.Set("id", id + 1)
w.WriteString("id:" + strconv.Itoa(id))
}