diff --git a/g/net/ghttp/http_server.go b/g/net/ghttp/http_server.go index 1da5ea53e..28b594192 100644 --- a/g/net/ghttp/http_server.go +++ b/g/net/ghttp/http_server.go @@ -7,44 +7,51 @@ package ghttp import ( - "strings" - "time" - "log" "sync" "errors" + "strings" "reflect" - "strconv" "net/http" - "crypto/tls" - "path/filepath" "gitee.com/johng/gf/g/util/gutil" "gitee.com/johng/gf/g/net/grouter" "gitee.com/johng/gf/g/container/gmap" "gitee.com/johng/gf/g/container/gqueue" "gitee.com/johng/gf/g/container/glist" "gitee.com/johng/gf/g/container/gtype" + "gitee.com/johng/gf/g/os/gcache" ) const ( - gDEFAULT_SERVER = "default" - gDEFAULT_DOMAIN = "default" - gDEFAULT_METHOD = "all" - gHTTP_METHODS = "GET,PUT,POST,DELETE,PATCH,HEAD,CONNECT,OPTIONS,TRACE" + gHTTP_METHODS = "GET,PUT,POST,DELETE,PATCH,HEAD,CONNECT,OPTIONS,TRACE" + gDEFAULT_SERVER = "default" + gDEFAULT_DOMAIN = "default" + gDEFAULT_METHOD = "all" + + gDEFAULT_COOKIE_PATH = "/" // 默认path + gDEFAULT_COOKIE_MAX_AGE = 86400*365 // 默认cookie有效期(一年) + gDEFAULT_SESSION_MAX_AGE = 600 // 默认session有效期(600秒) + gDEFAULT_SESSION_ID_NAME = "gfsessionid" // 默认存放Cookie中的SessionId名称 ) // http server结构体 type Server struct { - hmu sync.RWMutex // handlerMap互斥锁 - name string // 服务名称,方便识别 - server http.Server // 底层http server对象 - config ServerConfig // 配置对象 - status int8 // 当前服务器状态(0:未启动,1:运行中) - handlerMap HandlerMap // 所有注册的回调函数 - methodsMap map[string]bool // 所有支持的HTTP Method(初始化时自动填充) - servedCount *gtype.Int // 已经服务的请求数(4-8字节,不考虑溢出情况) - closeQueue *gqueue.Queue // 请求结束的关闭队列(存放的是需要异步关闭处理的*Request对象) - hooksMap *gmap.StringInterfaceMap // 钩子注册方法map,键值为按照注册顺序生成的glist,用于hook顺序调用 - Router *grouter.Router // 路由管理对象 + hmu sync.RWMutex // handlerMap互斥锁 + name string // 服务名称,方便识别 + server http.Server // 底层http server对象 + config ServerConfig // 配置对象 + status int8 // 当前服务器状态(0:未启动,1:运行中) + handlerMap HandlerMap // 所有注册的回调函数 + methodsMap map[string]bool // 所有支持的HTTP Method(初始化时自动填充) + closeQueue *gqueue.Queue // 请求结束的关闭队列(存放的是需要异步关闭处理的*Request对象) + hooksMap *gmap.StringInterfaceMap // 钩子注册方法map,键值为按照注册顺序生成的glist,用于hook顺序调用 + servedCount *gtype.Int // 已经服务的请求数(4-8字节,不考虑溢出情况) + cookieMaxAge *gtype.Int // Cookie有效期 + sessionMaxAge *gtype.Int // Session有效期 + sessionIdName *gtype.String // SessionId名称 + cookies *gmap.IntInterfaceMap // 当前服务器正在服务(请求正在执行)的Cookie(每个请求一个Cookie对象) + sessions *gcache.Cache // Session内存缓存 + + Router *grouter.Router // 路由管理对象 } // 域名、URI与回调函数的绑定记录表 @@ -74,13 +81,18 @@ func GetServer(names...string) (*Server) { return s.(*Server) } s := &Server{ - name : name, - handlerMap : make(HandlerMap), - methodsMap : make(map[string]bool), - servedCount : gtype.NewInt(), - closeQueue : gqueue.New(), - hooksMap : gmap.NewStringInterfaceMap(), - Router : grouter.New(), + name : name, + handlerMap : make(HandlerMap), + methodsMap : make(map[string]bool), + servedCount : gtype.NewInt(), + closeQueue : gqueue.New(), + hooksMap : gmap.NewStringInterfaceMap(), + Router : grouter.New(), + cookies : gmap.NewIntInterfaceMap(), + sessions : gcache.New(), + cookieMaxAge : gtype.NewInt(gDEFAULT_COOKIE_MAX_AGE), + sessionMaxAge : gtype.NewInt(gDEFAULT_SESSION_MAX_AGE), + sessionIdName : gtype.NewString(gDEFAULT_SESSION_ID_NAME), } for _, v := range strings.Split(gHTTP_METHODS, ",") { s.methodsMap[v] = true @@ -119,143 +131,6 @@ func (s *Server) Run() error { return nil } -// 获取 -func (s *Server) GetName() string { - return s.name -} - -// http server setting设置 -// 注意使用该方法进行http server配置时,需要配置所有的配置项,否则没有配置的属性将会默认变量为空 -func (s *Server)SetConfig(c ServerConfig) error { - if s.status == 1 { - return errors.New("server config cannot be changed while running") - } - if c.Handler == nil { - c.Handler = http.HandlerFunc(s.defaultHttpHandle) - } - s.config = c - // 需要处理server root最后的目录分隔符号 - if s.config.ServerRoot != "" { - s.SetServerRoot(s.config.ServerRoot) - } - // 必需设置默认值的属性 - if len(s.config.IndexFiles) < 1 { - s.SetIndexFiles(defaultServerConfig.IndexFiles) - } - if s.config.ServerAgent == "" { - s.SetServerAgent(defaultServerConfig.ServerAgent) - } - return nil -} - -// 设置http server参数 - Addr -func (s *Server)SetAddr(addr string) error { - if s.status == 1 { - return errors.New("server config cannot be changed while running") - } - s.config.Addr = addr - return nil -} - -// 设置http server参数 - Port -func (s *Server)SetPort(port int) error { - if s.status == 1 { - return errors.New("server config cannot be changed while running") - } - s.config.Addr = ":" + strconv.Itoa(port) - return nil -} - -// 设置http server参数 - TLSConfig -func (s *Server)SetTLSConfig(tls *tls.Config) error { - if s.status == 1 { - return errors.New("server config cannot be changed while running") - } - s.config.TLSConfig = tls - return nil -} - -// 设置http server参数 - ReadTimeout -func (s *Server)SetReadTimeout(t time.Duration) error { - if s.status == 1 { - return errors.New("server config cannot be changed while running") - } - s.config.ReadTimeout = t - return nil -} - -// 设置http server参数 - WriteTimeout -func (s *Server)SetWriteTimeout(t time.Duration) error { - if s.status == 1 { - return errors.New("server config cannot be changed while running") - } - s.config.WriteTimeout = t - return nil -} - -// 设置http server参数 - IdleTimeout -func (s *Server)SetIdleTimeout(t time.Duration) error { - if s.status == 1 { - return errors.New("server config cannot be changed while running") - } - s.config.IdleTimeout = t - return nil -} - -// 设置http server参数 - MaxHeaderBytes -func (s *Server)SetMaxHeaderBytes(b int) error { - if s.status == 1 { - return errors.New("server config cannot be changed while running") - } - s.config.MaxHeaderBytes = b - return nil -} - -// 设置http server参数 - ErrorLog -func (s *Server)SetErrorLog(logger *log.Logger) error { - if s.status == 1 { - return errors.New("server config cannot be changed while running") - } - s.config.ErrorLog = logger - return nil -} - -// 设置http server参数 - IndexFiles -func (s *Server)SetIndexFiles(index []string) error { - if s.status == 1 { - return errors.New("server config cannot be changed while running") - } - s.config.IndexFiles = index - return nil -} - -// 设置http server参数 - IndexFolder -func (s *Server)SetIndexFolder(index bool) error { - if s.status == 1 { - return errors.New("server config cannot be changed while running") - } - s.config.IndexFolder = index - return nil -} - -// 设置http server参数 - ServerAgent -func (s *Server)SetServerAgent(agent string) error { - if s.status == 1 { - return errors.New("server config cannot be changed while running") - } - s.config.ServerAgent = agent - return nil -} - -// 设置http server参数 - ServerRoot -func (s *Server)SetServerRoot(root string) error { - if s.status == 1 { - return errors.New("server config cannot be changed while running") - } - s.config.ServerRoot = strings.TrimRight(root, string(filepath.Separator)) - return nil -} - // 生成回调方法查询的Key func (s *Server) handlerKey(domain, method, pattern string) string { return strings.ToUpper(method) + ":" + pattern + "@" + strings.ToLower(domain) @@ -374,7 +249,7 @@ func (s *Server)BindObject(pattern string, obj interface{}) error { } // 绑定对象到URI请求处理中,会自动识别方法名称,并附加到对应的URI地址后面 -// 第三个参数methods支持多个方法注册,多个方法以英文“,”号分隔,不区分大小写 +// 第三个参数methods支持多个方法注册,多个方法以英文“,”号分隔,区分大小写 func (s *Server)BindObjectMethod(pattern string, obj interface{}, methods string) error { m := make(HandlerMap) for _, v := range strings.Split(methods, ",") { diff --git a/g/net/ghttp/http_server_config.go b/g/net/ghttp/http_server_config.go index 6c13974c3..c78f6a8e0 100644 --- a/g/net/ghttp/http_server_config.go +++ b/g/net/ghttp/http_server_config.go @@ -8,10 +8,10 @@ package ghttp import ( - "net/http" - "crypto/tls" "time" "log" + "net/http" + "crypto/tls" ) // HTTP Server 设置结构体 diff --git a/g/net/ghttp/http_server_cookie.go b/g/net/ghttp/http_server_cookie.go index f5aab3c1f..f7b16afde 100644 --- a/g/net/ghttp/http_server_cookie.go +++ b/g/net/ghttp/http_server_cookie.go @@ -15,13 +15,6 @@ import ( "strings" "net/http" "gitee.com/johng/gf/g/os/gtime" - "gitee.com/johng/gf/g/container/gmap" -) - -const ( - gDEFAULT_PATH = "/" // 默认path - gDEFAULT_MAX_AGE = 86400*365 // 默认cookie有效期(一年) - SESSION_ID_NAME = "gfsessionid" // 默认存放Cookie中的SessionId名称 ) // cookie对象 @@ -29,6 +22,7 @@ type Cookie struct { mu sync.RWMutex // 并发安全互斥锁 data map[string]CookieItem // 数据项 domain string // 默认的cookie域名 + server *Server // 所属Server request *Request // 所属HTTP请求对象 response *Response // 所属HTTP返回对象 } @@ -41,52 +35,37 @@ type CookieItem struct { expire int // 过期时间 } -// 包含所有当前服务器正在服务的Cookie(每个请求一个Cookie对象) -var cookies = gmap.NewUintInterfaceMap() - -// 创建一个cookie对象,与传入的请求对应 -func NewCookie(r *Request) *Cookie { - if r := GetCookie(r.Id); r != nil { - return r +// 获取或者创建一个cookie对象,与传入的请求对应 +func GetCookie(r *Request) *Cookie { + if v := r.Server.cookies.Get(r.Id); v != nil { + return v.(*Cookie) } c := &Cookie { data : make(map[string]CookieItem), - domain : defaultDomain(r), + domain : strings.Split(r.Host, ":")[0], + server : r.Server, request : r, response : r.Response, } c.init() - cookies.Set(uint(r.Id), c) + c.server.cookies.Set(r.Id, c) return c } -// 获取一个已经存在的Cookie对象 -func GetCookie(requestid int) *Cookie { - if r := cookies.Get(uint(requestid)); r != nil { - return r.(*Cookie) - } - return nil -} - -// 获取默认的domain参数 -func defaultDomain(r *Request) string { - return strings.Split(r.Host, ":")[0] -} - // 从请求流中初始化 func (c *Cookie) init() { c.mu.Lock() - defer c.mu.Unlock() for _, v := range c.request.Cookies() { c.data[v.Name] = CookieItem { v.Value, v.Domain, v.Path, v.Expires.Second(), } } + c.mu.Unlock() } // 获取SessionId func (c *Cookie) SessionId() string { - v := c.Get(SESSION_ID_NAME) + v := c.Get(c.server.GetSessionIdName()) if v == "" { v = makeSessionId() c.SetSessionId(v) @@ -96,12 +75,12 @@ func (c *Cookie) SessionId() string { // 设置SessionId func (c *Cookie) SetSessionId(sessionid string) { - c.Set(SESSION_ID_NAME, sessionid) + c.Set(c.server.GetSessionIdName(), sessionid) } // 设置cookie,使用默认参数 func (c *Cookie) Set(key, value string) { - c.SetCookie(key, value, c.domain, gDEFAULT_PATH, gDEFAULT_MAX_AGE) + c.SetCookie(key, value, c.domain, gDEFAULT_COOKIE_PATH, c.server.GetCookieMaxAge()) } // 设置cookie,带详细cookie参数 @@ -135,13 +114,12 @@ func (c *Cookie) Remove(key, domain, path string) { // 请求完毕后删除已经存在的Cookie对象 func (c *Cookie) Close() { - cookies.Remove(uint(c.request.Id)) + c.server.cookies.Remove(c.request.Id) } // 输出到客户端 func (c *Cookie) Output() { c.mu.RLock() - defer c.mu.RUnlock() for k, v := range c.data { if v.expire == 0 { continue @@ -157,4 +135,5 @@ func (c *Cookie) Output() { }, ) } + c.mu.RUnlock() } diff --git a/g/net/ghttp/http_server_domain.go b/g/net/ghttp/http_server_domain.go index 7bae5868a..3a11a6523 100644 --- a/g/net/ghttp/http_server_domain.go +++ b/g/net/ghttp/http_server_domain.go @@ -98,7 +98,7 @@ func (d *Domain) BindControllerRest(pattern string, c Controller) error { return nil } -// 控制器方法注册,methods参数不区分大小写 +// 控制器方法注册,methods参数区分大小写 func (d *Domain) BindControllerMethod(pattern string, c Controller, methods string) error { for domain, _ := range d.m { if err := d.s.BindControllerMethod(pattern + "@" + domain, c, methods); err != nil { diff --git a/g/net/ghttp/http_server_handler.go b/g/net/ghttp/http_server_handler.go index 6fd23fc81..b710e6ba4 100644 --- a/g/net/ghttp/http_server_handler.go +++ b/g/net/ghttp/http_server_handler.go @@ -61,8 +61,8 @@ func (s *Server)handleRequest(w http.ResponseWriter, r *http.Request) { // 初始化控制器 func (s *Server)callHandler(h *HandlerItem, r *Request) { // 会话处理 - r.Cookie = NewCookie(r) - r.Session = GetSession(r.Cookie.SessionId()) + r.Cookie = GetCookie(r) + r.Session = GetSession(r) // 请求处理 s.callHookHandler(r, "BeforeServe") diff --git a/g/net/ghttp/http_server_options.go b/g/net/ghttp/http_server_options.go new file mode 100644 index 000000000..a26ed90a6 --- /dev/null +++ b/g/net/ghttp/http_server_options.go @@ -0,0 +1,186 @@ +// Copyright 2018 gf Author(https://gitee.com/johng/gf). All Rights Reserved. +// +// 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 ghttp + +import ( + "strings" + "time" + "log" + "errors" + "strconv" + "net/http" + "crypto/tls" + "path/filepath" +) + +// http server setting设置 +// 注意使用该方法进行http server配置时,需要配置所有的配置项,否则没有配置的属性将会默认变量为空 +func (s *Server)SetConfig(c ServerConfig) error { + if s.status == 1 { + return errors.New("server config cannot be changed while running") + } + if c.Handler == nil { + c.Handler = http.HandlerFunc(s.defaultHttpHandle) + } + s.config = c + // 需要处理server root最后的目录分隔符号 + if s.config.ServerRoot != "" { + s.SetServerRoot(s.config.ServerRoot) + } + // 必需设置默认值的属性 + if len(s.config.IndexFiles) < 1 { + s.SetIndexFiles(defaultServerConfig.IndexFiles) + } + if s.config.ServerAgent == "" { + s.SetServerAgent(defaultServerConfig.ServerAgent) + } + return nil +} + +// 设置http server参数 - Addr +func (s *Server)SetAddr(addr string) error { + if s.status == 1 { + return errors.New("server config cannot be changed while running") + } + s.config.Addr = addr + return nil +} + +// 设置http server参数 - Port +func (s *Server)SetPort(port int) error { + if s.status == 1 { + return errors.New("server config cannot be changed while running") + } + s.config.Addr = ":" + strconv.Itoa(port) + return nil +} + +// 设置http server参数 - TLSConfig +func (s *Server)SetTLSConfig(tls *tls.Config) error { + if s.status == 1 { + return errors.New("server config cannot be changed while running") + } + s.config.TLSConfig = tls + return nil +} + +// 设置http server参数 - ReadTimeout +func (s *Server)SetReadTimeout(t time.Duration) error { + if s.status == 1 { + return errors.New("server config cannot be changed while running") + } + s.config.ReadTimeout = t + return nil +} + +// 设置http server参数 - WriteTimeout +func (s *Server)SetWriteTimeout(t time.Duration) error { + if s.status == 1 { + return errors.New("server config cannot be changed while running") + } + s.config.WriteTimeout = t + return nil +} + +// 设置http server参数 - IdleTimeout +func (s *Server)SetIdleTimeout(t time.Duration) error { + if s.status == 1 { + return errors.New("server config cannot be changed while running") + } + s.config.IdleTimeout = t + return nil +} + +// 设置http server参数 - MaxHeaderBytes +func (s *Server)SetMaxHeaderBytes(b int) error { + if s.status == 1 { + return errors.New("server config cannot be changed while running") + } + s.config.MaxHeaderBytes = b + return nil +} + +// 设置http server参数 - ErrorLog +func (s *Server)SetErrorLog(logger *log.Logger) error { + if s.status == 1 { + return errors.New("server config cannot be changed while running") + } + s.config.ErrorLog = logger + return nil +} + +// 设置http server参数 - IndexFiles +func (s *Server)SetIndexFiles(index []string) error { + if s.status == 1 { + return errors.New("server config cannot be changed while running") + } + s.config.IndexFiles = index + return nil +} + +// 设置http server参数 - IndexFolder +func (s *Server)SetIndexFolder(index bool) error { + if s.status == 1 { + return errors.New("server config cannot be changed while running") + } + s.config.IndexFolder = index + return nil +} + +// 设置http server参数 - ServerAgent +func (s *Server)SetServerAgent(agent string) error { + if s.status == 1 { + return errors.New("server config cannot be changed while running") + } + s.config.ServerAgent = agent + return nil +} + +// 设置http server参数 - ServerRoot +func (s *Server)SetServerRoot(root string) error { + if s.status == 1 { + return errors.New("server config cannot be changed while running") + } + s.config.ServerRoot = strings.TrimRight(root, string(filepath.Separator)) + return nil +} + +// 设置http server参数 - CookieMaxAge +func (s *Server)SetCookieMaxAge(maxage int) { + s.cookieMaxAge.Set(maxage) +} + +// 设置http server参数 - SessionMaxAge +func (s *Server)SetSessionMaxAge(maxage int) { + s.sessionMaxAge.Set(maxage) +} + +// 设置http server参数 - SessionIdName +func (s *Server)SetSessionIdName(name string) { + s.sessionIdName.Set(name) +} + + +// 获取 +func (s *Server) GetName() string { + return s.name +} + +// 获取http server参数 - CookieMaxAge +func (s *Server)GetCookieMaxAge() int { + return s.cookieMaxAge.Val() +} + +// 获取http server参数 - SessionMaxAge +func (s *Server)GetSessionMaxAge() int { + return s.sessionMaxAge.Val() +} + +// 获取http server参数 - SessionIdName +func (s *Server)GetSessionIdName() string { + return s.sessionIdName.Val() +} diff --git a/g/net/ghttp/http_server_session.go b/g/net/ghttp/http_server_session.go index a0da2486f..e043596ab 100644 --- a/g/net/ghttp/http_server_session.go +++ b/g/net/ghttp/http_server_session.go @@ -12,48 +12,37 @@ import ( "strconv" "strings" "gitee.com/johng/gf/g/os/gtime" - "gitee.com/johng/gf/g/os/gcache" "gitee.com/johng/gf/g/util/grand" - "gitee.com/johng/gf/g/container/gmap" "gitee.com/johng/gf/g/util/gconv" - "sync/atomic" + "gitee.com/johng/gf/g/container/gmap" ) // 单个session对象 type Session struct { mu sync.RWMutex // 并发安全互斥锁 - id string // sessionid - data *gmap.StringInterfaceMap // session数据 + id string // SessionId + data *gmap.StringInterfaceMap // Session数据 + server *Server // 所属Server } -// 默认session过期时间(秒) -var defaultSessionMaxAge int32 = 600 - // 生成一个唯一的sessionid字符串 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 GetSession(sessionid string) *Session { - if r := gcache.Get(sessionCacheKey(sessionid)); r != nil { +func GetSession(r *Request) *Session { + s := r.Server + sid := r.Cookie.SessionId() + if r := s.sessions.Get(sid); r != nil { return r.(*Session) } - s := &Session { - id : sessionid, + ses := &Session { + id : sid, data : gmap.NewStringInterfaceMap(), + server : s, } - return s -} - -// session在gache中的缓存键名 -func sessionCacheKey(sessionid string) string { - return "session_" + sessionid + return ses } // 获取sessionid @@ -112,5 +101,5 @@ func (s *Session) Remove (k string) { // 更新过期时间(如果用在守护进程中长期使用,需要手动调用进行更新,防止超时被清除) func (s *Session) UpdateExpire() { - gcache.Set(sessionCacheKey(s.id), s, int64(defaultSessionMaxAge*1000)) + s.server.sessions.Set(s.id, s, int64(s.server.sessionMaxAge.Val()*1000)) } \ No newline at end of file diff --git a/geg/net/ghttp/events.go b/geg/net/ghttp/events.go index 30d8a65f0..f62646f8f 100644 --- a/geg/net/ghttp/events.go +++ b/geg/net/ghttp/events.go @@ -23,5 +23,4 @@ func main() { ghttp.GetServer().SetPort(10000) ghttp.GetServer().Run() - select { } } \ No newline at end of file diff --git a/geg/other/test.go b/geg/other/test.go index 974cd0ad5..a7fd01173 100644 --- a/geg/other/test.go +++ b/geg/other/test.go @@ -2,9 +2,17 @@ package main import ( "fmt" - "math" + "reflect" ) +type T struct { + +} + +func (t *T) Test2Test() {} + func main() { - fmt.Println(math.MaxInt64) + obj := &T{} + v := reflect.ValueOf(obj).MethodByName("Test2Test") + fmt.Println(v.IsValid()) } \ No newline at end of file