mirror of
https://gitee.com/johng/gf
synced 2026-06-27 09:47:19 +08:00
ghttp路由功能改进中
This commit is contained in:
@ -27,7 +27,6 @@ import (
|
||||
"github.com/gorilla/websocket"
|
||||
"gitee.com/johng/gf/g/os/gtime"
|
||||
"time"
|
||||
"container/list"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -43,6 +42,8 @@ const (
|
||||
gDEFAULT_COOKIE_MAX_AGE = 86400*365 // 默认cookie有效期(一年)
|
||||
gDEFAULT_SESSION_MAX_AGE = 600 // 默认session有效期(600秒)
|
||||
gDEFAULT_SESSION_ID_NAME = "gfsessionid" // 默认存放Cookie中的SessionId名称
|
||||
gSERVE_CACHE_LRU_SIZE = 100000 // 服务回调函数缓存LRU大小
|
||||
gHOOKS_CACHE_LRU_SIZE = 100000 // 事件回调函数缓存LRU大小
|
||||
)
|
||||
|
||||
// ghttp.Server结构体
|
||||
@ -56,8 +57,9 @@ type Server struct {
|
||||
servedCount *gtype.Int // 已经服务的请求数(4-8字节,不考虑溢出情况),同时作为请求ID
|
||||
closeQueue *gqueue.Queue // 请求结束的关闭队列(存放的是需要异步关闭处理的*Request对象)
|
||||
// 服务注册相关
|
||||
handlerTree map[string]interface{} // 所有注册的回调函数(路由表,树型结构,哈希表+链表优先级匹配)
|
||||
handlerCache *gcache.Cache // 服务注册路由内存缓存
|
||||
serveTree map[string]interface{} // 所有注册的服务回调函数(路由表,树型结构,哈希表+链表优先级匹配)
|
||||
hooksTree map[string]interface{} // 所有注册的事件回调函数(路由表,树型结构,哈希表+链表优先级匹配)
|
||||
serveCache *gcache.Cache // 服务注册路由内存缓存
|
||||
hooksCache *gcache.Cache // 事件回调路由内存缓存
|
||||
// 自定义状态码回调
|
||||
hsmu sync.RWMutex // status handler互斥锁
|
||||
@ -88,7 +90,7 @@ type Router struct {
|
||||
Priority int // 优先级,用于链表排序,值越大优先级越高
|
||||
}
|
||||
|
||||
// 域名、URI与回调函数的绑定记录表
|
||||
// pattern与回调函数的绑定map
|
||||
type handlerMap map[string]*handlerItem
|
||||
|
||||
// http回调函数注册信息
|
||||
@ -96,19 +98,13 @@ type handlerItem struct {
|
||||
ctype reflect.Type // 控制器类型(反射类型)
|
||||
fname string // 回调方法名称
|
||||
faddr HandlerFunc // 准确的执行方法内存地址(与以上两个参数二选一)
|
||||
}
|
||||
|
||||
// 路由注册项(这里使用了非并发安全的list.List,因为该对象的使用统一是由htmu互斥锁保证并发安全)
|
||||
type handlerRegisterItem struct {
|
||||
handler *handlerItem // 准确的执行方法内存地址
|
||||
hooks map[string]*list.List // 当前的事件回调注册,键名为事件名称,键值为事件执行方法链表
|
||||
router *Router // 注册时绑定的路由对象
|
||||
router *Router // 注册时绑定的路由对象
|
||||
}
|
||||
|
||||
// 根据特定URL.Path解析后的路由检索结果项
|
||||
type handlerParsedItem struct {
|
||||
item *handlerRegisterItem // 路由注册项
|
||||
values map[string][]string // 特定URL.Path的Router解析参数
|
||||
item *handlerItem // 路由注册项
|
||||
values map[string][]string // 特定URL.Path的Router解析参数
|
||||
}
|
||||
|
||||
// HTTP注册函数
|
||||
@ -172,8 +168,9 @@ func GetServer(name...interface{}) (*Server) {
|
||||
servers : make([]*gracefulServer, 0),
|
||||
methodsMap : make(map[string]bool),
|
||||
statusHandlerMap : make(map[string]HandlerFunc),
|
||||
handlerTree : make(map[string]interface{}),
|
||||
handlerCache : gcache.New(),
|
||||
serveTree : make(map[string]interface{}),
|
||||
hooksTree : make(map[string]interface{}),
|
||||
serveCache : gcache.New(),
|
||||
hooksCache : gcache.New(),
|
||||
cookies : gmap.NewIntInterfaceMap(),
|
||||
sessions : gcache.New(),
|
||||
@ -192,8 +189,8 @@ func GetServer(name...interface{}) (*Server) {
|
||||
s.errorLogger.SetBacktraceSkip(4)
|
||||
s.accessLogger.SetBacktraceSkip(4)
|
||||
// 设置路由解析缓存上限,使用LRU进行缓存淘汰
|
||||
s.hooksCache.SetCap(10000)
|
||||
s.handlerCache.SetCap(10000)
|
||||
s.serveCache.SetCap(gSERVE_CACHE_LRU_SIZE)
|
||||
s.hooksCache.SetCap(gHOOKS_CACHE_LRU_SIZE)
|
||||
for _, v := range strings.Split(gHTTP_METHODS, ",") {
|
||||
s.methodsMap[v] = true
|
||||
}
|
||||
|
||||
@ -70,7 +70,7 @@ func (s *Server)parsePattern(pattern string) (domain, method, uri string, err er
|
||||
func (s *Server) setHandler(pattern string, handler *handlerItem, hook ... string) error {
|
||||
// Web Server正字运行时无法动态注册路由方法
|
||||
if s.Status() == SERVER_STATUS_RUNNING {
|
||||
return errors.New("cannnot bind handler while server running")
|
||||
return errors.New("cannot bind handler while server running")
|
||||
}
|
||||
var hookName string
|
||||
if len(hook) > 0 {
|
||||
@ -82,34 +82,28 @@ func (s *Server) setHandler(pattern string, handler *handlerItem, hook ... strin
|
||||
}
|
||||
|
||||
// 路由对象
|
||||
router := &Router {
|
||||
handler.router = &Router {
|
||||
Uri : uri,
|
||||
Domain : domain,
|
||||
Method : method,
|
||||
Priority : strings.Count(uri[1:], "/"),
|
||||
}
|
||||
router.RegRule, router.RegNames = s.patternToRegRule(uri)
|
||||
|
||||
// 注册对象
|
||||
registerItem := &handlerRegisterItem {
|
||||
handler : handler,
|
||||
hooks : make(map[string]*list.List),
|
||||
router : router,
|
||||
}
|
||||
if len(hookName) > 0 {
|
||||
registerItem.handler = nil
|
||||
registerItem.hooks[hookName] = list.New()
|
||||
registerItem.hooks[hookName].PushBack(handler)
|
||||
}
|
||||
handler.router.RegRule, handler.router.RegNames = s.patternToRegRule(uri)
|
||||
|
||||
// 动态注册,首先需要判断是否是动态注册,如果不是那么就没必要添加到动态注册记录变量中。
|
||||
// 非叶节点为哈希表检索节点,按照URI注册的层级进行高效检索,直至到叶子链表节点;
|
||||
// 叶子节点是链表,按照优先级进行排序,优先级高的排前面,按照遍历检索,按照哈希表层级检索后的叶子链表数据量不会很大,所以效率比较高;
|
||||
if _, ok := s.handlerTree[domain]; !ok {
|
||||
s.handlerTree[domain] = make(map[string]interface{})
|
||||
tree := (map[string]interface{})(nil)
|
||||
if len(hookName) == 0 {
|
||||
tree = s.serveTree
|
||||
} else {
|
||||
tree = s.hooksTree
|
||||
}
|
||||
if _, ok := tree[domain]; !ok {
|
||||
tree[domain] = make(map[string]interface{})
|
||||
}
|
||||
// 用于遍历的指针
|
||||
p := s.handlerTree[domain]
|
||||
p := tree[domain]
|
||||
// 当前节点的规则链表
|
||||
lists := make([]*list.List, 0)
|
||||
array := ([]string)(nil)
|
||||
@ -153,79 +147,29 @@ func (s *Server) setHandler(pattern string, handler *handlerItem, hook ... strin
|
||||
}
|
||||
// 得到的lists是该路由规则一路匹配下来相关的模糊匹配链表(注意不是这棵树所有的链表),
|
||||
// 从头开始遍历每个节点的模糊匹配链表,将该路由项插入进去(按照优先级高的放在前面)
|
||||
item := (*handlerRegisterItem)(nil)
|
||||
// 用以标记 *handlerRegisterItem 指向的对象是否已经处理过,因为多个节点可能会关联同一个该对象
|
||||
pushedItemSet := gset.NewStringSet()
|
||||
if len(hookName) == 0 {
|
||||
// 普通方法路由注册,追加或者覆盖
|
||||
for _, l := range lists {
|
||||
pushed := false
|
||||
address := ""
|
||||
for e := l.Front(); e != nil; e = e.Next() {
|
||||
item = e.Value.(*handlerRegisterItem)
|
||||
address = fmt.Sprintf("%p", item)
|
||||
if pushedItemSet.Contains(address) {
|
||||
pushed = true
|
||||
break
|
||||
}
|
||||
// 判断是否已存在相同的路由注册项
|
||||
if strings.EqualFold(router.Domain, item.router.Domain) &&
|
||||
strings.EqualFold(router.Method, item.router.Method) &&
|
||||
strings.EqualFold(router.Uri, item.router.Uri) {
|
||||
item.handler = handler
|
||||
pushed = true
|
||||
break
|
||||
}
|
||||
if s.compareRouterPriority(router, item.router) {
|
||||
l.InsertBefore(registerItem, e)
|
||||
item := (*handlerItem)(nil)
|
||||
for _, l := range lists {
|
||||
pushed := false
|
||||
for e := l.Front(); e != nil; e = e.Next() {
|
||||
item = e.Value.(*handlerItem)
|
||||
// 判断是否已存在相同的路由注册项
|
||||
if len(hookName) == 0 {
|
||||
if strings.EqualFold(handler.router.Domain, item.router.Domain) &&
|
||||
strings.EqualFold(handler.router.Method, item.router.Method) &&
|
||||
strings.EqualFold(handler.router.Uri, item.router.Uri) {
|
||||
e.Value = handler
|
||||
pushed = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if pushed {
|
||||
if len(address) > 0 {
|
||||
pushedItemSet.Add(address)
|
||||
}
|
||||
} else {
|
||||
l.PushBack(registerItem)
|
||||
if s.compareRouterPriority(handler.router, item.router) {
|
||||
l.InsertBefore(handler, e)
|
||||
pushed = true
|
||||
break
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 回调方法路由注册,将方法追加到链表末尾
|
||||
for _, l := range lists {
|
||||
pushed := false
|
||||
address := ""
|
||||
for e := l.Front(); e != nil; e = e.Next() {
|
||||
item = e.Value.(*handlerRegisterItem)
|
||||
address = fmt.Sprintf("%p", item)
|
||||
if pushedItemSet.Contains(address) {
|
||||
pushed = true
|
||||
break
|
||||
}
|
||||
// 判断是否已存在相同的路由注册项
|
||||
if strings.EqualFold(router.Domain, item.router.Domain) &&
|
||||
strings.EqualFold(router.Method, item.router.Method) &&
|
||||
strings.EqualFold(router.Uri, item.router.Uri) {
|
||||
if _, ok := item.hooks[hookName]; !ok {
|
||||
item.hooks[hookName] = list.New()
|
||||
}
|
||||
item.hooks[hookName].PushBack(handler)
|
||||
pushed = true
|
||||
break
|
||||
}
|
||||
if s.compareRouterPriority(router, item.router) {
|
||||
l.InsertBefore(registerItem, e)
|
||||
pushed = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if pushed {
|
||||
if len(address) > 0 {
|
||||
pushedItemSet.Add(address)
|
||||
}
|
||||
} else {
|
||||
l.PushBack(registerItem)
|
||||
}
|
||||
if !pushed {
|
||||
l.PushBack(handler)
|
||||
}
|
||||
}
|
||||
//gutil.Dump(s.handlerTree)
|
||||
|
||||
Reference in New Issue
Block a user