ghttp组件优化

This commit is contained in:
John
2018-04-10 10:32:37 +08:00
parent c4b9144d45
commit 24b8c2459e
9 changed files with 269 additions and 233 deletions

View File

@ -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, ",") {

View File

@ -8,10 +8,10 @@
package ghttp
import (
"net/http"
"crypto/tls"
"time"
"log"
"net/http"
"crypto/tls"
)
// HTTP Server 设置结构体

View File

@ -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()
}

View File

@ -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 {

View File

@ -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")

View File

@ -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()
}

View File

@ -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))
}

View File

@ -23,5 +23,4 @@ func main() {
ghttp.GetServer().SetPort(10000)
ghttp.GetServer().Run()
select { }
}

View File

@ -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())
}