mirror of
https://gitee.com/johng/gf
synced 2026-07-08 22:40:30 +08:00
完成ghttp.Server服务注册与事件回调注册的动态路由规则特性
This commit is contained in:
@ -31,8 +31,8 @@ const (
|
|||||||
|
|
||||||
// http server结构体
|
// http server结构体
|
||||||
type Server struct {
|
type Server struct {
|
||||||
hmmu sync.RWMutex // handlerMap互斥锁
|
hmmu sync.RWMutex // handler互斥锁
|
||||||
htmu sync.RWMutex // handlerTree互斥锁
|
hhmu sync.RWMutex // hooks互斥锁
|
||||||
name string // 服务名称,方便识别
|
name string // 服务名称,方便识别
|
||||||
server http.Server // 底层http server对象
|
server http.Server // 底层http server对象
|
||||||
config ServerConfig // 配置对象
|
config ServerConfig // 配置对象
|
||||||
@ -40,15 +40,16 @@ type Server struct {
|
|||||||
methodsMap map[string]bool // 所有支持的HTTP Method(初始化时自动填充)
|
methodsMap map[string]bool // 所有支持的HTTP Method(初始化时自动填充)
|
||||||
handlerMap HandlerMap // 所有注册的回调函数(静态匹配)
|
handlerMap HandlerMap // 所有注册的回调函数(静态匹配)
|
||||||
handlerTree map[string]interface{} // 所有注册的回调函数(动态匹配,树型+链表优先级匹配)
|
handlerTree map[string]interface{} // 所有注册的回调函数(动态匹配,树型+链表优先级匹配)
|
||||||
hooksMap *gmap.StringInterfaceMap // 钩子注册方法map,键值为按照注册顺序生成的glist,用于hook顺序调用
|
hooksTree map[string]interface{} // 所有注册的事件回调函数(动态匹配,树型+链表优先级匹配)
|
||||||
closeQueue *gqueue.Queue // 请求结束的关闭队列(存放的是需要异步关闭处理的*Request对象)
|
handlerCache *gcache.Cache // 服务注册路由内存缓存
|
||||||
|
hooksCache *gcache.Cache // 回调事件注册路由内存缓存
|
||||||
servedCount *gtype.Int // 已经服务的请求数(4-8字节,不考虑溢出情况)
|
servedCount *gtype.Int // 已经服务的请求数(4-8字节,不考虑溢出情况)
|
||||||
cookieMaxAge *gtype.Int // Cookie有效期
|
cookieMaxAge *gtype.Int // Cookie有效期
|
||||||
sessionMaxAge *gtype.Int // Session有效期
|
sessionMaxAge *gtype.Int // Session有效期
|
||||||
sessionIdName *gtype.String // SessionId名称
|
sessionIdName *gtype.String // SessionId名称
|
||||||
routers *gcache.Cache // 服务注册路由内存缓存
|
|
||||||
cookies *gmap.IntInterfaceMap // 当前服务器正在服务(请求正在执行)的Cookie(每个请求一个Cookie对象)
|
cookies *gmap.IntInterfaceMap // 当前服务器正在服务(请求正在执行)的Cookie(每个请求一个Cookie对象)
|
||||||
sessions *gcache.Cache // Session内存缓存
|
sessions *gcache.Cache // Session内存缓存
|
||||||
|
closeQueue *gqueue.Queue // 请求结束的关闭队列(存放的是需要异步关闭处理的*Request对象)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 域名、URI与回调函数的绑定记录表
|
// 域名、URI与回调函数的绑定记录表
|
||||||
@ -86,16 +87,19 @@ func GetServer(names...string) (*Server) {
|
|||||||
methodsMap : make(map[string]bool),
|
methodsMap : make(map[string]bool),
|
||||||
handlerMap : make(HandlerMap),
|
handlerMap : make(HandlerMap),
|
||||||
handlerTree : make(map[string]interface{}),
|
handlerTree : make(map[string]interface{}),
|
||||||
hooksMap : gmap.NewStringInterfaceMap(),
|
hooksTree : make(map[string]interface{}),
|
||||||
servedCount : gtype.NewInt(),
|
handlerCache : gcache.New(),
|
||||||
closeQueue : gqueue.New(),
|
hooksCache : gcache.New(),
|
||||||
routers : gcache.New(),
|
|
||||||
cookies : gmap.NewIntInterfaceMap(),
|
cookies : gmap.NewIntInterfaceMap(),
|
||||||
sessions : gcache.New(),
|
sessions : gcache.New(),
|
||||||
cookieMaxAge : gtype.NewInt(gDEFAULT_COOKIE_MAX_AGE),
|
cookieMaxAge : gtype.NewInt(gDEFAULT_COOKIE_MAX_AGE),
|
||||||
sessionMaxAge : gtype.NewInt(gDEFAULT_SESSION_MAX_AGE),
|
sessionMaxAge : gtype.NewInt(gDEFAULT_SESSION_MAX_AGE),
|
||||||
sessionIdName : gtype.NewString(gDEFAULT_SESSION_ID_NAME),
|
sessionIdName : gtype.NewString(gDEFAULT_SESSION_ID_NAME),
|
||||||
|
servedCount : gtype.NewInt(),
|
||||||
|
closeQueue : gqueue.New(),
|
||||||
}
|
}
|
||||||
|
s.hooksCache.SetCap(10000)
|
||||||
|
s.handlerCache.SetCap(10000)
|
||||||
for _, v := range strings.Split(gHTTP_METHODS, ",") {
|
for _, v := range strings.Split(gHTTP_METHODS, ",") {
|
||||||
s.methodsMap[v] = true
|
s.methodsMap[v] = true
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,9 +17,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"gitee.com/johng/gf/g/os/gfile"
|
"gitee.com/johng/gf/g/os/gfile"
|
||||||
"gitee.com/johng/gf/g/util/gregx"
|
|
||||||
"gitee.com/johng/gf/g/encoding/ghtml"
|
"gitee.com/johng/gf/g/encoding/ghtml"
|
||||||
"gitee.com/johng/gf/g/container/glist"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// 默认HTTP Server处理入口,http包底层默认使用了gorutine异步处理请求,所以这里不再异步执行
|
// 默认HTTP Server处理入口,http包底层默认使用了gorutine异步处理请求,所以这里不再异步执行
|
||||||
@ -40,83 +38,6 @@ func (s *Server)handleRequest(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 查询请求处理方法
|
|
||||||
// 这里有个锁机制,可以并发读,但是不能并发写
|
|
||||||
func (s *Server) getHandler(r *Request) *HandlerItem {
|
|
||||||
handler := s.searchHandler(r)
|
|
||||||
return handler
|
|
||||||
}
|
|
||||||
|
|
||||||
// 按照指定hook回调函数的注册顺序进行调用
|
|
||||||
func (s *Server)callHookHandler(r *Request, hook string) {
|
|
||||||
l := s.searchHookHandler(r, hook)
|
|
||||||
if l != nil {
|
|
||||||
for _, f := range l {
|
|
||||||
f(r)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取指定hook的回调函数列表,按照注册顺序排序
|
|
||||||
func (s *Server)searchHookHandler(r *Request, hook string) []HandlerFunc {
|
|
||||||
domains := []string{gDEFAULT_DOMAIN, strings.Split(r.Host, ":")[0]}
|
|
||||||
// 首先进行静态匹配
|
|
||||||
for _, domain := range domains {
|
|
||||||
key := s.handlerHookKey(domain, r.Method, r.URL.Path, hook)
|
|
||||||
if v := s.hooksMap.Get(key); v != nil {
|
|
||||||
items := v.(*glist.List).FrontAll()
|
|
||||||
funcs := make([]HandlerFunc, len(items))
|
|
||||||
for k, v := range items {
|
|
||||||
funcs[k] = v.(HandlerFunc)
|
|
||||||
}
|
|
||||||
return funcs
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 其次进行正则匹配(会比较耗效率)
|
|
||||||
var funcs []HandlerFunc
|
|
||||||
s.hooksMap.Iterator(func(rule string, list interface{}) bool {
|
|
||||||
if array, err := gregx.MatchString(`([a-zA-Z]+)\^([a-zA-Z]+):(.+)@([\w\.\-]+)`, rule); len(array) > 3 && err == nil {
|
|
||||||
// hook匹配
|
|
||||||
if !strings.EqualFold(hook, array[1]) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
// method匹配
|
|
||||||
if !strings.EqualFold(r.Method, array[2]) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
// domain匹配
|
|
||||||
for _, domain := range domains {
|
|
||||||
if !strings.EqualFold(domain, array[4]) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
// method & domain匹配时,那么执行pattern的正则匹配
|
|
||||||
regrule, querystr := s.patternToRegRule(array[3])
|
|
||||||
if gregx.IsMatchString(regrule, r.URL.Path) {
|
|
||||||
// 如果需要query匹配,那么需要重新解析URL
|
|
||||||
if len(querystr) > 0 {
|
|
||||||
if query, err := gregx.ReplaceString(regrule, querystr, r.URL.Path); err == nil && len(query) > 0 {
|
|
||||||
if vals, err := url.ParseQuery(query); err == nil {
|
|
||||||
for k, v := range vals {
|
|
||||||
r.values[k] = v
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 列表数据解析
|
|
||||||
items := list.(*glist.List).FrontAll()
|
|
||||||
funcs = make([]HandlerFunc, len(items))
|
|
||||||
for k, v := range items {
|
|
||||||
funcs[k] = v.(HandlerFunc)
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
return funcs
|
|
||||||
}
|
|
||||||
|
|
||||||
// 初始化控制器
|
// 初始化控制器
|
||||||
func (s *Server)callHandler(h *HandlerItem, r *Request) {
|
func (s *Server)callHandler(h *HandlerItem, r *Request) {
|
||||||
// 会话处理
|
// 会话处理
|
||||||
|
|||||||
210
g/net/ghttp/http_server_hooks.go
Normal file
210
g/net/ghttp/http_server_hooks.go
Normal file
@ -0,0 +1,210 @@
|
|||||||
|
// 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 (
|
||||||
|
"errors"
|
||||||
|
"strings"
|
||||||
|
"container/list"
|
||||||
|
"gitee.com/johng/gf/g/util/gregx"
|
||||||
|
)
|
||||||
|
|
||||||
|
// hook缓存项,根据URL.Path进行缓存,因此对象中带有缓存参数
|
||||||
|
type hookCacheItem struct {
|
||||||
|
faddr HandlerFunc // 准确的执行方法内存地址
|
||||||
|
values map[string][]string // GET解析参数
|
||||||
|
}
|
||||||
|
|
||||||
|
// 事件回调注册方法
|
||||||
|
func (s *Server) setHookHandler(pattern string, hook string, item *HandlerItem) error {
|
||||||
|
domain, method, uri, err := s.parsePattern(pattern)
|
||||||
|
if err != nil {
|
||||||
|
return errors.New("invalid pattern")
|
||||||
|
}
|
||||||
|
item.uri = uri
|
||||||
|
item.domain = domain
|
||||||
|
item.method = method
|
||||||
|
|
||||||
|
s.hhmu.Lock()
|
||||||
|
defer s.hhmu.Unlock()
|
||||||
|
if _, ok := s.hooksTree[domain]; !ok {
|
||||||
|
s.hooksTree[domain] = make(map[string]interface{})
|
||||||
|
}
|
||||||
|
p := s.hooksTree[domain]
|
||||||
|
if _, ok := p.(map[string]interface{})[hook]; !ok {
|
||||||
|
p.(map[string]interface{})[hook] = make(map[string]interface{})
|
||||||
|
}
|
||||||
|
p = p.(map[string]interface{})[hook]
|
||||||
|
|
||||||
|
array := strings.Split(uri[1:], "/")
|
||||||
|
item.priority = len(array)
|
||||||
|
for _, v := range array {
|
||||||
|
if len(v) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
switch v[0] {
|
||||||
|
case ':':
|
||||||
|
fallthrough
|
||||||
|
case '*':
|
||||||
|
v = "/"
|
||||||
|
fallthrough
|
||||||
|
default:
|
||||||
|
if _, ok := p.(map[string]interface{})[v]; !ok {
|
||||||
|
p.(map[string]interface{})[v] = make(map[string]interface{})
|
||||||
|
}
|
||||||
|
p = p.(map[string]interface{})[v]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 到达叶子节点
|
||||||
|
var l *list.List
|
||||||
|
if v, ok := p.(map[string]interface{})["*list"]; !ok {
|
||||||
|
l = list.New()
|
||||||
|
p.(map[string]interface{})["*list"] = l
|
||||||
|
} else {
|
||||||
|
l = v.(*list.List)
|
||||||
|
}
|
||||||
|
// 从头开始遍历链表,优先级高的放在前面
|
||||||
|
for e := l.Front(); e != nil; e = e.Next() {
|
||||||
|
if s.compareHandlerItemPriority(item, e.Value.(*HandlerItem)) {
|
||||||
|
l.InsertBefore(item, e)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
l.PushBack(item)
|
||||||
|
|
||||||
|
//b,_ := gjson.New(s.hooksTree).ToJsonIndent()
|
||||||
|
//fmt.Println(string(b))
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 事件回调 - 检索动态路由规则
|
||||||
|
// 并按照指定hook回调函数的优先级及注册顺序进行调用
|
||||||
|
func (s *Server) callHookHandler(r *Request, hook string) {
|
||||||
|
var hookItems []*hookCacheItem
|
||||||
|
cacheKey := hook + "^" + r.URL.Path
|
||||||
|
if v := s.hooksCache.Get(cacheKey); v == nil {
|
||||||
|
hookItems = s.searchHookHandler(r, hook)
|
||||||
|
if hookItems != nil {
|
||||||
|
s.hooksCache.Set(cacheKey, hookItems, 0)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
hookItems = v.([]*hookCacheItem)
|
||||||
|
}
|
||||||
|
if hookItems != nil {
|
||||||
|
for _, item := range hookItems {
|
||||||
|
for k, v := range item.values {
|
||||||
|
r.values[k] = v
|
||||||
|
}
|
||||||
|
item.faddr(r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) searchHookHandler(r *Request, hook string) []*hookCacheItem {
|
||||||
|
// 一般不会注册事件回调,因此优先判断大小
|
||||||
|
if len(s.hooksTree) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
s.hhmu.RLock()
|
||||||
|
defer s.hhmu.RUnlock()
|
||||||
|
hookItems := make([]*hookCacheItem, 0)
|
||||||
|
domains := []string{gDEFAULT_DOMAIN, strings.Split(r.Host, ":")[0]}
|
||||||
|
array := strings.Split(r.URL.Path[1:], "/")
|
||||||
|
for _, domain := range domains {
|
||||||
|
p, ok := s.hooksTree[domain]
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
p, ok = p.(map[string]interface{})[hook]
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// 多层链表的目的是当叶子节点未有任何规则匹配时,让父级模糊匹配规则继续处理
|
||||||
|
lists := make([]*list.List, 0)
|
||||||
|
for k, v := range array {
|
||||||
|
if _, ok := p.(map[string]interface{})["*list"]; ok {
|
||||||
|
lists = append(lists, p.(map[string]interface{})["*list"].(*list.List))
|
||||||
|
}
|
||||||
|
if _, ok := p.(map[string]interface{})[v]; !ok {
|
||||||
|
if _, ok := p.(map[string]interface{})["/"]; ok {
|
||||||
|
p = p.(map[string]interface{})["/"]
|
||||||
|
if k == len(array) - 1 {
|
||||||
|
if _, ok := p.(map[string]interface{})["*list"]; ok {
|
||||||
|
lists = append(lists, p.(map[string]interface{})["*list"].(*list.List))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
p = p.(map[string]interface{})[v]
|
||||||
|
if k == len(array) - 1 {
|
||||||
|
if _, ok := p.(map[string]interface{})["*list"]; ok {
|
||||||
|
lists = append(lists, p.(map[string]interface{})["*list"].(*list.List))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 多层链表遍历检索,从数组末尾的链表开始遍历,末尾的深度高优先级也高
|
||||||
|
for i := len(lists) - 1; i >= 0; i-- {
|
||||||
|
for e := lists[i].Front(); e != nil; e = e.Next() {
|
||||||
|
item := e.Value.(*HandlerItem)
|
||||||
|
if strings.EqualFold(item.method, gDEFAULT_METHOD) || strings.EqualFold(item.method, r.Method) {
|
||||||
|
regrule, names := s.patternToRegRule(item.uri)
|
||||||
|
if gregx.IsMatchString(regrule, r.URL.Path) {
|
||||||
|
hookItem := &hookCacheItem {item.faddr, nil}
|
||||||
|
// 如果需要query匹配,那么需要重新解析URL
|
||||||
|
if len(names) > 0 {
|
||||||
|
if match, err := gregx.MatchString(regrule, r.URL.Path); err == nil {
|
||||||
|
array := strings.Split(names, ",")
|
||||||
|
if len(match) > len(array) {
|
||||||
|
hookItem.values = make(map[string][]string)
|
||||||
|
// 这里需要注意的是,注册事件回调如果带有规则匹配,那么会修改Request对象传递参数的值
|
||||||
|
// 这个应当在注册事件回调的时候注意
|
||||||
|
for index, name := range array {
|
||||||
|
hookItem.values[name] = []string{match[index + 1]}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
hookItems = append(hookItems, hookItem)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return hookItems
|
||||||
|
}
|
||||||
|
|
||||||
|
// 绑定指定的hook回调函数, pattern参数同BindHandler,支持命名路由;hook参数的值由ghttp server设定,参数不区分大小写
|
||||||
|
func (s *Server)BindHookHandler(pattern string, hook string, handler HandlerFunc) error {
|
||||||
|
return s.setHookHandler(pattern, hook, &HandlerItem{
|
||||||
|
ctype : nil,
|
||||||
|
fname : "",
|
||||||
|
faddr : handler,
|
||||||
|
})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 通过map批量绑定回调函数
|
||||||
|
func (s *Server)BindHookHandlerByMap(pattern string, hookmap map[string]HandlerFunc) error {
|
||||||
|
for k, v := range hookmap {
|
||||||
|
if err := s.BindHookHandler(pattern, k, v); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构造用于hooksMap检索的键名
|
||||||
|
func (s *Server)handlerHookKey(domain, method, uri, hook string) string {
|
||||||
|
return strings.ToUpper(hook) + "^" + s.handlerKey(domain, method, uri)
|
||||||
|
}
|
||||||
@ -14,8 +14,35 @@ import (
|
|||||||
"gitee.com/johng/gf/g/util/gregx"
|
"gitee.com/johng/gf/g/util/gregx"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// handler缓存项,根据URL.Path进行缓存,因此对象中带有缓存参数
|
||||||
|
type handlerCacheItem struct {
|
||||||
|
item *HandlerItem // 准确的执行方法内存地址
|
||||||
|
values map[string][]string // GET解析参数
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询请求处理方法
|
||||||
|
// 这里有个锁机制,可以并发读,但是不能并发写
|
||||||
|
func (s *Server) getHandler(r *Request) *HandlerItem {
|
||||||
|
var handlerItem *handlerCacheItem
|
||||||
|
if v := s.handlerCache.Get(r.URL.Path); v == nil {
|
||||||
|
handlerItem = s.searchHandler(r)
|
||||||
|
if handlerItem != nil {
|
||||||
|
s.handlerCache.Set(r.URL.Path, handlerItem, 0)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
handlerItem = v.(*handlerCacheItem)
|
||||||
|
}
|
||||||
|
if handlerItem != nil {
|
||||||
|
for k, v := range handlerItem.values {
|
||||||
|
r.values[k] = v
|
||||||
|
}
|
||||||
|
return handlerItem.item
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// 解析pattern
|
// 解析pattern
|
||||||
func (s *Server)parsePatternForBindHandler(pattern string) (domain, method, uri string, err error) {
|
func (s *Server)parsePattern(pattern string) (domain, method, uri string, err error) {
|
||||||
uri = pattern
|
uri = pattern
|
||||||
domain = gDEFAULT_DOMAIN
|
domain = gDEFAULT_DOMAIN
|
||||||
method = gDEFAULT_METHOD
|
method = gDEFAULT_METHOD
|
||||||
@ -35,7 +62,7 @@ func (s *Server)parsePatternForBindHandler(pattern string) (domain, method, uri
|
|||||||
|
|
||||||
// 注册服务处理方法
|
// 注册服务处理方法
|
||||||
func (s *Server) setHandler(pattern string, item *HandlerItem) error {
|
func (s *Server) setHandler(pattern string, item *HandlerItem) error {
|
||||||
domain, method, uri, err := s.parsePatternForBindHandler(pattern)
|
domain, method, uri, err := s.parsePattern(pattern)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("invalid pattern")
|
return errors.New("invalid pattern")
|
||||||
}
|
}
|
||||||
@ -57,8 +84,6 @@ func (s *Server) setHandler(pattern string, item *HandlerItem) error {
|
|||||||
// 非叶节点为哈希表检索节点,按照URI注册的层级进行高效检索,直至到叶子链表节点;
|
// 非叶节点为哈希表检索节点,按照URI注册的层级进行高效检索,直至到叶子链表节点;
|
||||||
// 叶子节点是链表,按照优先级进行排序,优先级高的排前面,按照遍历检索,按照哈希表层级检索后的叶子链表一般数据量不大,所以效率比较高;
|
// 叶子节点是链表,按照优先级进行排序,优先级高的排前面,按照遍历检索,按照哈希表层级检索后的叶子链表一般数据量不大,所以效率比较高;
|
||||||
if s.isUriHasRule(uri) {
|
if s.isUriHasRule(uri) {
|
||||||
s.htmu.Lock()
|
|
||||||
defer s.htmu.Unlock()
|
|
||||||
if _, ok := s.handlerTree[domain]; !ok {
|
if _, ok := s.handlerTree[domain]; !ok {
|
||||||
s.handlerTree[domain] = make(map[string]interface{})
|
s.handlerTree[domain] = make(map[string]interface{})
|
||||||
}
|
}
|
||||||
@ -120,42 +145,42 @@ func (s *Server) compareHandlerItemPriority(newItem, oldItem *HandlerItem) bool
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 服务方法检索
|
// 服务方法检索
|
||||||
func (s *Server) searchHandler(r *Request) *HandlerItem {
|
func (s *Server) searchHandler(r *Request) *handlerCacheItem {
|
||||||
f := s.searchHandlerStatic(r)
|
item := s.searchHandlerStatic(r)
|
||||||
if f == nil {
|
if item == nil {
|
||||||
f = s.searchHandlerDynamic(r)
|
item = s.searchHandlerDynamic(r)
|
||||||
}
|
}
|
||||||
// 如果检索不到服务,那么使用默认的"/"服务注册来执行服务
|
// 如果检索不到服务,那么使用默认的"/"服务注册来执行服务
|
||||||
// "/"静态路由是特殊的路由,当所有服务都找不到时,会交给"/"路由规则的控制器来处理
|
// "/"静态路由是特殊的路由,当所有服务都找不到时,会交给"/"路由规则的控制器来处理
|
||||||
if f == nil && r.URL.Path != "/" {
|
if item == nil && r.URL.Path != "/" {
|
||||||
path := r.URL.Path
|
path := r.URL.Path
|
||||||
r.URL.Path = "/"
|
r.URL.Path = "/"
|
||||||
f = s.searchHandlerStatic(r)
|
item = s.searchHandlerStatic(r)
|
||||||
r.URL.Path = path
|
r.URL.Path = path
|
||||||
}
|
}
|
||||||
return f
|
return item
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检索静态路由规则
|
// 检索静态路由规则
|
||||||
func (s *Server) searchHandlerStatic(r *Request) *HandlerItem {
|
func (s *Server) searchHandlerStatic(r *Request) *handlerCacheItem {
|
||||||
s.hmmu.RLock()
|
s.hmmu.RLock()
|
||||||
defer s.hmmu.RUnlock()
|
defer s.hmmu.RUnlock()
|
||||||
domains := []string{gDEFAULT_DOMAIN, strings.Split(r.Host, ":")[0]}
|
domains := []string{gDEFAULT_DOMAIN, strings.Split(r.Host, ":")[0]}
|
||||||
// 首先进行静态匹配
|
// 首先进行静态匹配
|
||||||
for _, domain := range domains {
|
for _, domain := range domains {
|
||||||
if f, ok := s.handlerMap[s.handlerKey(domain, r.Method, r.URL.Path)]; ok {
|
if f, ok := s.handlerMap[s.handlerKey(domain, r.Method, r.URL.Path)]; ok {
|
||||||
return f
|
return &handlerCacheItem{f, nil}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检索动态路由规则
|
// 检索动态路由规则
|
||||||
func (s *Server) searchHandlerDynamic(r *Request) *HandlerItem {
|
func (s *Server) searchHandlerDynamic(r *Request) *handlerCacheItem {
|
||||||
|
s.hmmu.RLock()
|
||||||
|
defer s.hmmu.RUnlock()
|
||||||
domains := []string{gDEFAULT_DOMAIN, strings.Split(r.Host, ":")[0]}
|
domains := []string{gDEFAULT_DOMAIN, strings.Split(r.Host, ":")[0]}
|
||||||
array := strings.Split(r.URL.Path[1:], "/")
|
array := strings.Split(r.URL.Path[1:], "/")
|
||||||
s.htmu.RLock()
|
|
||||||
defer s.htmu.RLock()
|
|
||||||
for _, domain := range domains {
|
for _, domain := range domains {
|
||||||
p, ok := s.handlerTree[domain]
|
p, ok := s.handlerTree[domain]
|
||||||
if !ok {
|
if !ok {
|
||||||
@ -175,6 +200,8 @@ func (s *Server) searchHandlerDynamic(r *Request) *HandlerItem {
|
|||||||
lists = append(lists, p.(map[string]interface{})["*list"].(*list.List))
|
lists = append(lists, p.(map[string]interface{})["*list"].(*list.List))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
break
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
p = p.(map[string]interface{})[v]
|
p = p.(map[string]interface{})[v]
|
||||||
@ -193,18 +220,20 @@ func (s *Server) searchHandlerDynamic(r *Request) *HandlerItem {
|
|||||||
if strings.EqualFold(item.method, gDEFAULT_METHOD) || strings.EqualFold(item.method, r.Method) {
|
if strings.EqualFold(item.method, gDEFAULT_METHOD) || strings.EqualFold(item.method, r.Method) {
|
||||||
regrule, names := s.patternToRegRule(item.uri)
|
regrule, names := s.patternToRegRule(item.uri)
|
||||||
if gregx.IsMatchString(regrule, r.URL.Path) {
|
if gregx.IsMatchString(regrule, r.URL.Path) {
|
||||||
|
handlerItem := &handlerCacheItem{item, nil}
|
||||||
// 如果需要query匹配,那么需要重新解析URL
|
// 如果需要query匹配,那么需要重新解析URL
|
||||||
if len(names) > 0 {
|
if len(names) > 0 {
|
||||||
if match, err := gregx.MatchString(regrule, r.URL.Path); err == nil {
|
if match, err := gregx.MatchString(regrule, r.URL.Path); err == nil {
|
||||||
array := strings.Split(names, ",")
|
array := strings.Split(names, ",")
|
||||||
if len(match) > len(array) {
|
if len(match) > len(array) {
|
||||||
|
handlerItem.values = make(map[string][]string)
|
||||||
for index, name := range array {
|
for index, name := range array {
|
||||||
r.values[name] = []string{match[index + 1]}
|
handlerItem.values[name] = []string{match[index + 1]}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return item
|
return handlerItem
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -197,41 +197,3 @@ func (s *Server)BindControllerMethod(pattern string, c Controller, methods strin
|
|||||||
}
|
}
|
||||||
return s.bindHandlerByMap(m)
|
return s.bindHandlerByMap(m)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 绑定指定的hook回调函数, pattern参数同BindHandler,支持命名路由;hook参数的值由ghttp server设定,参数不区分大小写
|
|
||||||
func (s *Server)BindHookHandler(pattern string, hook string, handler HandlerFunc) error {
|
|
||||||
//domain, method, uri, err := s.parsePatternForBindHookHandler(pattern)
|
|
||||||
//if err != nil {
|
|
||||||
// return errors.New("invalid pattern")
|
|
||||||
//}
|
|
||||||
//var l *glist.List
|
|
||||||
//if method == gDEFAULT_METHOD {
|
|
||||||
// for v, _ := range s.methodsMap {
|
|
||||||
// if v := s.hooksMap.GetWithDefault(s.handlerHookKey(domain, v, uri, hook), glist.New()); v != nil {
|
|
||||||
// l = v.(*glist.List)
|
|
||||||
// }
|
|
||||||
// l.PushBack(handler)
|
|
||||||
// }
|
|
||||||
//} else {
|
|
||||||
// if v := s.hooksMap.GetWithDefault(s.handlerHookKey(domain, method, uri, hook), glist.New()); v == nil {
|
|
||||||
// l = v.(*glist.List)
|
|
||||||
// }
|
|
||||||
// l.PushBack(handler)
|
|
||||||
//}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// 通过map批量绑定回调函数
|
|
||||||
func (s *Server)BindHookHandlerByMap(pattern string, hookmap map[string]HandlerFunc) error {
|
|
||||||
for k, v := range hookmap {
|
|
||||||
if err := s.BindHookHandler(pattern, k, v); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// 构造用于hooksMap检索的键名
|
|
||||||
func (s *Server)handlerHookKey(domain, method, uri, hook string) string {
|
|
||||||
return strings.ToUpper(hook) + "^" + s.handlerKey(domain, method, uri)
|
|
||||||
}
|
|
||||||
|
|||||||
@ -6,7 +6,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
pattern := "/"
|
pattern := "/:name/action"
|
||||||
ghttp.GetServer().BindHookHandlerByMap(pattern, map[string]ghttp.HandlerFunc{
|
ghttp.GetServer().BindHookHandlerByMap(pattern, map[string]ghttp.HandlerFunc{
|
||||||
"BeforeServe" : func(r *ghttp.Request){ fmt.Println("BeforeServe") },
|
"BeforeServe" : func(r *ghttp.Request){ fmt.Println("BeforeServe") },
|
||||||
"AfterServe" : func(r *ghttp.Request){ fmt.Println("AfterServe") },
|
"AfterServe" : func(r *ghttp.Request){ fmt.Println("AfterServe") },
|
||||||
|
|||||||
@ -7,19 +7,19 @@ func main() {
|
|||||||
r.Response.WriteString("hello world")
|
r.Response.WriteString("hello world")
|
||||||
})
|
})
|
||||||
|
|
||||||
//ghttp.GetServer().BindHandler("/:name/*any", func(r *ghttp.Request) {
|
ghttp.GetServer().BindHandler("/:name/*any", func(r *ghttp.Request) {
|
||||||
// r.Response.WriteString("any")
|
r.Response.WriteString("any")
|
||||||
|
r.Response.WriteString(r.GetQueryString("name"))
|
||||||
|
r.Response.WriteString(r.GetQueryString("any"))
|
||||||
|
})
|
||||||
|
//ghttp.GetServer().BindHandler("/:name/action", func(r *ghttp.Request) {
|
||||||
// r.Response.WriteString(r.GetQueryString("name"))
|
// r.Response.WriteString(r.GetQueryString("name"))
|
||||||
// r.Response.WriteString(r.GetQueryString("any"))
|
|
||||||
//})
|
|
||||||
////ghttp.GetServer().BindHandler("/:name/action", func(r *ghttp.Request) {
|
|
||||||
//// r.Response.WriteString(r.GetQueryString("name"))
|
|
||||||
////})
|
|
||||||
//ghttp.GetServer().BindHandler("/:name/:action/:aaa", func(r *ghttp.Request) {
|
|
||||||
// r.Response.WriteString("name")
|
|
||||||
// r.Response.WriteString(r.GetQueryString("name"))
|
|
||||||
// r.Response.WriteString(r.GetQueryString("action"))
|
|
||||||
//})
|
//})
|
||||||
|
ghttp.GetServer().BindHandler("/:name/:action/:aaa", func(r *ghttp.Request) {
|
||||||
|
r.Response.WriteString("name")
|
||||||
|
r.Response.WriteString(r.GetQueryString("name"))
|
||||||
|
r.Response.WriteString(r.GetQueryString("action"))
|
||||||
|
})
|
||||||
ghttp.GetServer().SetPort(10000)
|
ghttp.GetServer().SetPort(10000)
|
||||||
ghttp.GetServer().Run()
|
ghttp.GetServer().Run()
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user