mirror of
https://gitee.com/johng/gf.git
synced 2024-12-02 12:17:53 +08:00
add middleware feature for ghttp.Server
This commit is contained in:
parent
0460a53f53
commit
878305fee3
@ -10,6 +10,7 @@ package glist
|
||||
|
||||
import (
|
||||
"container/list"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/gogf/gf/internal/rwmutex"
|
||||
)
|
||||
@ -371,3 +372,8 @@ func (l *List) IteratorDesc(f func(e *Element) bool) {
|
||||
}
|
||||
l.mu.RUnlock()
|
||||
}
|
||||
|
||||
// MarshalJSON implements the interface MarshalJSON for json.Marshal.
|
||||
func (l *List) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(l.FrontAll())
|
||||
}
|
||||
|
@ -21,27 +21,28 @@ import (
|
||||
// 请求对象
|
||||
type Request struct {
|
||||
*http.Request
|
||||
Id int // 请求ID(当前Server对象唯一)
|
||||
Server *Server // 请求关联的服务器对象
|
||||
Cookie *Cookie // 与当前请求绑定的Cookie对象(并发安全)
|
||||
Session *Session // 与当前请求绑定的Session对象(并发安全)
|
||||
Response *Response // 对应请求的返回数据操作对象
|
||||
Router *Router // 匹配到的路由对象
|
||||
EnterTime int64 // 请求进入时间(微秒)
|
||||
LeaveTime int64 // 请求完成时间(微秒)
|
||||
MiddleWare *MiddleWare // 中间件功能调用对象
|
||||
handlers []*handlerParsedItem // 请求执行服务函数列表(包含中间件、路由函数、钩子函数)
|
||||
handlerIndex int // 当前执行函数的索引号
|
||||
parsedGet bool // GET参数是否已经解析
|
||||
parsedPost bool // POST参数是否已经解析
|
||||
queryVars map[string][]string // GET参数
|
||||
routerVars map[string][]string // 路由解析参数
|
||||
exit bool // 是否退出当前请求流程执行
|
||||
params map[string]interface{} // 开发者自定义参数(请求流程中有效)
|
||||
parsedHost string // 解析过后不带端口号的服务器域名名称
|
||||
clientIp string // 解析过后的客户端IP地址
|
||||
rawContent []byte // 客户端提交的原始参数
|
||||
isFileRequest bool // 是否为静态文件请求(非服务请求,当静态文件存在时,优先级会被服务请求高,被识别为文件请求)
|
||||
Id int // 请求ID(当前Server对象唯一)
|
||||
Server *Server // 请求关联的服务器对象
|
||||
Cookie *Cookie // 与当前请求绑定的Cookie对象(并发安全)
|
||||
Session *Session // 与当前请求绑定的Session对象(并发安全)
|
||||
Response *Response // 对应请求的返回数据操作对象
|
||||
Router *Router // 匹配到的路由对象
|
||||
EnterTime int64 // 请求进入时间(微秒)
|
||||
LeaveTime int64 // 请求完成时间(微秒)
|
||||
MiddleWare *MiddleWare // 中间件功能调用对象
|
||||
handlers []*handlerParsedItem // 请求执行服务函数列表(包含中间件、路由函数、钩子函数)
|
||||
handlerIndex int // 当前执行函数的索引号
|
||||
hasHookHandler bool // 是否注册有钩子函数(用于请求时提高钩子函数功能启用判断效率)
|
||||
parsedGet bool // GET参数是否已经解析
|
||||
parsedPost bool // POST参数是否已经解析
|
||||
queryVars map[string][]string // GET参数
|
||||
routerVars map[string][]string // 路由解析参数
|
||||
exit bool // 是否退出当前请求流程执行
|
||||
params map[string]interface{} // 开发者自定义参数(请求流程中有效)
|
||||
parsedHost string // 解析过后不带端口号的服务器域名名称
|
||||
clientIp string // 解析过后的客户端IP地址
|
||||
rawContent []byte // 客户端提交的原始参数
|
||||
isFileRequest bool // 是否为静态文件请求(非服务请求,当静态文件存在时,优先级会被服务请求高,被识别为文件请求)
|
||||
}
|
||||
|
||||
// 创建一个Request对象
|
||||
|
23
net/ghttp/ghttp_request_hook.go
Normal file
23
net/ghttp/ghttp_request_hook.go
Normal file
@ -0,0 +1,23 @@
|
||||
// Copyright 2017 gf Author(https://github.com/gogf/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://github.com/gogf/gf.
|
||||
|
||||
package ghttp
|
||||
|
||||
// 获得当前请求,指定类型的的钩子函数列表
|
||||
func (r *Request) getHookHandlers(hook string) []*handlerParsedItem {
|
||||
if !r.hasHookHandler {
|
||||
return nil
|
||||
}
|
||||
parsedItems := make([]*handlerParsedItem, 0, 4)
|
||||
for _, v := range r.handlers {
|
||||
if v.handler.hookName != hook {
|
||||
continue
|
||||
}
|
||||
item := v
|
||||
parsedItems = append(parsedItems, item)
|
||||
}
|
||||
return parsedItems
|
||||
}
|
@ -16,12 +16,13 @@ type MiddleWare struct {
|
||||
// 执行下一个请求流程处理函数
|
||||
func (m *MiddleWare) Next() {
|
||||
item := (*handlerParsedItem)(nil)
|
||||
for ; m.request.handlerIndex < len(m.request.handlers); m.request.handlerIndex++ {
|
||||
for {
|
||||
// 是否停止请求执行
|
||||
if m.request.IsExited() {
|
||||
if m.request.IsExited() || m.request.handlerIndex >= len(m.request.handlers) {
|
||||
return
|
||||
}
|
||||
item = m.request.handlers[m.request.handlerIndex]
|
||||
m.request.handlerIndex++
|
||||
// 通过中间件模式不执行钩子函数
|
||||
if item.handler.itemType == gHANDLER_TYPE_HOOK {
|
||||
continue
|
||||
@ -38,12 +39,12 @@ func (m *MiddleWare) Next() {
|
||||
niceCallFunc(func() {
|
||||
c.MethodByName("Init").Call([]reflect.Value{reflect.ValueOf(m.request)})
|
||||
})
|
||||
if m.request.IsExited() {
|
||||
if !m.request.IsExited() {
|
||||
niceCallFunc(func() {
|
||||
c.MethodByName(item.handler.ctrlInfo.name).Call(nil)
|
||||
})
|
||||
}
|
||||
if m.request.IsExited() {
|
||||
if !m.request.IsExited() {
|
||||
niceCallFunc(func() {
|
||||
c.MethodByName("Shut").Call(nil)
|
||||
})
|
||||
@ -54,12 +55,12 @@ func (m *MiddleWare) Next() {
|
||||
item.handler.initFunc(m.request)
|
||||
})
|
||||
}
|
||||
if m.request.IsExited() {
|
||||
if !m.request.IsExited() {
|
||||
niceCallFunc(func() {
|
||||
item.handler.itemFunc(m.request)
|
||||
})
|
||||
}
|
||||
if m.request.IsExited() && item.handler.shutFunc != nil {
|
||||
if !m.request.IsExited() && item.handler.shutFunc != nil {
|
||||
niceCallFunc(func() {
|
||||
item.handler.shutFunc(m.request)
|
||||
})
|
||||
|
@ -42,10 +42,7 @@ type (
|
||||
closeChan chan struct{} // 用以关闭事件通知的通道
|
||||
servedCount *gtype.Int // 已经服务的请求数(4-8字节,不考虑溢出情况),同时作为请求ID
|
||||
serveTree map[string]interface{} // 所有注册的服务回调函数(路由表,树型结构,哈希表+链表优先级匹配)
|
||||
hooksTree map[string]interface{} // 所有注册的事件回调函数(路由表,树型结构,哈希表+链表优先级匹配)
|
||||
middlewareTree map[string]interface{} // 所有注册的中间件(路由表,树型结构,哈希表+链表优先级匹配)
|
||||
serveCache *gcache.Cache // 服务注册路由内存缓存
|
||||
hooksCache *gcache.Cache // 事件回调路由内存缓存
|
||||
routesMap map[string][]registeredRouteItem // 已经注册的路由及对应的注册方法文件地址(用以路由重复注册判断)
|
||||
statusHandlerMap map[string]HandlerFunc // 不同状态码下的注册处理方法(例如404状态时的处理方法)
|
||||
sessions *gcache.Cache // Session内存缓存
|
||||
@ -65,11 +62,12 @@ type (
|
||||
// 服务函数注册信息
|
||||
handlerItem struct {
|
||||
itemName string // 注册的函数名称信息(用于路由信息打印)
|
||||
itemType int // 注册函数类型(对象/函数/控制器/中间件)
|
||||
itemType int // 注册函数类型(对象/函数/控制器/中间件/钩子函数)
|
||||
itemFunc HandlerFunc // 函数内存地址(与以上两个参数二选一)
|
||||
initFunc HandlerFunc // 初始化请求回调函数(对象注册方式下有效)
|
||||
shutFunc HandlerFunc // 完成请求回调函数(对象注册方式下有效)
|
||||
ctrlInfo *handlerController // 控制器服务函数反射信息
|
||||
hookName string // 钩子类型名称(注册函数类型为钩子函数下有效)
|
||||
router *Router // 注册时绑定的路由对象
|
||||
}
|
||||
|
||||
@ -208,9 +206,7 @@ func GetServer(name ...interface{}) *Server {
|
||||
serverCount: gtype.NewInt(),
|
||||
statusHandlerMap: make(map[string]HandlerFunc),
|
||||
serveTree: make(map[string]interface{}),
|
||||
hooksTree: make(map[string]interface{}),
|
||||
serveCache: gcache.New(),
|
||||
hooksCache: gcache.New(),
|
||||
routesMap: make(map[string][]registeredRouteItem),
|
||||
sessions: gcache.New(),
|
||||
servedCount: gtype.NewInt(),
|
||||
|
@ -97,7 +97,7 @@ func (s *Server) handleRequest(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// 动态服务检索
|
||||
if !request.isFileRequest || isStaticDir {
|
||||
request.handlers = s.getHandlersWithCache(request)
|
||||
request.handlers, request.hasHookHandler = s.getHandlersWithCache(request)
|
||||
}
|
||||
|
||||
// 判断最终对该请求提供的服务方式
|
||||
@ -114,7 +114,7 @@ func (s *Server) handleRequest(w http.ResponseWriter, r *http.Request) {
|
||||
// 静态服务
|
||||
s.serveFile(request, staticFile)
|
||||
} else {
|
||||
if request.handlers != nil {
|
||||
if len(request.handlers) > 0 {
|
||||
// 动态服务
|
||||
request.MiddleWare.Next()
|
||||
} else {
|
||||
|
@ -7,12 +7,13 @@
|
||||
package ghttp
|
||||
|
||||
import (
|
||||
"container/list"
|
||||
"errors"
|
||||
"fmt"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/gogf/gf/container/glist"
|
||||
|
||||
"github.com/gogf/gf/os/glog"
|
||||
"github.com/gogf/gf/text/gregex"
|
||||
"github.com/gogf/gf/text/gstr"
|
||||
@ -101,16 +102,8 @@ func (s *Server) setHandler(pattern string, handler *handlerItem, hook ...string
|
||||
if _, ok := s.serveTree[domain]; !ok {
|
||||
s.serveTree[domain] = make(map[string]interface{})
|
||||
}
|
||||
// 用于遍历的指针
|
||||
p := s.serveTree[domain]
|
||||
if len(hookName) > 0 {
|
||||
if _, ok := p.(map[string]interface{})[hookName]; !ok {
|
||||
p.(map[string]interface{})[hookName] = make(map[string]interface{})
|
||||
}
|
||||
p = p.(map[string]interface{})[hookName]
|
||||
}
|
||||
// 当前节点的规则链表
|
||||
lists := make([]*list.List, 0)
|
||||
lists := make([]*glist.List, 0)
|
||||
array := ([]string)(nil)
|
||||
if strings.EqualFold("/", uri) {
|
||||
array = []string{"/"}
|
||||
@ -118,7 +111,8 @@ func (s *Server) setHandler(pattern string, handler *handlerItem, hook ...string
|
||||
array = strings.Split(uri[1:], "/")
|
||||
}
|
||||
// 键名"*fuzz"代表模糊匹配节点,其下会有一个链表;
|
||||
// 键名"*list"代表链表,叶子节点和模糊匹配节点都有该属性;
|
||||
// 键名"*list"代表链表,叶子节点和模糊匹配节点都有该属性,优先级越高越排前;
|
||||
p := s.serveTree[domain]
|
||||
for k, v := range array {
|
||||
if len(v) == 0 {
|
||||
continue
|
||||
@ -129,10 +123,10 @@ func (s *Server) setHandler(pattern string, handler *handlerItem, hook ...string
|
||||
// 由于是模糊规则,因此这里会有一个*list,用以将后续的路由规则加进来,
|
||||
// 检索会从叶子节点的链表往根节点按照优先级进行检索
|
||||
if v, ok := p.(map[string]interface{})["*list"]; !ok {
|
||||
p.(map[string]interface{})["*list"] = list.New()
|
||||
lists = append(lists, p.(map[string]interface{})["*list"].(*list.List))
|
||||
p.(map[string]interface{})["*list"] = glist.New()
|
||||
lists = append(lists, p.(map[string]interface{})["*list"].(*glist.List))
|
||||
} else {
|
||||
lists = append(lists, v.(*list.List))
|
||||
lists = append(lists, v.(*glist.List))
|
||||
}
|
||||
}
|
||||
// 属性层级数据写入
|
||||
@ -143,10 +137,10 @@ func (s *Server) setHandler(pattern string, handler *handlerItem, hook ...string
|
||||
// 到达叶子节点,往list中增加匹配规则(条件 v != "*fuzz" 是因为模糊节点的话在前面已经添加了*list链表)
|
||||
if k == len(array)-1 && v != "*fuzz" {
|
||||
if v, ok := p.(map[string]interface{})["*list"]; !ok {
|
||||
p.(map[string]interface{})["*list"] = list.New()
|
||||
lists = append(lists, p.(map[string]interface{})["*list"].(*list.List))
|
||||
p.(map[string]interface{})["*list"] = glist.New()
|
||||
lists = append(lists, p.(map[string]interface{})["*list"].(*glist.List))
|
||||
} else {
|
||||
lists = append(lists, v.(*list.List))
|
||||
lists = append(lists, v.(*glist.List))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -160,15 +154,14 @@ func (s *Server) setHandler(pattern string, handler *handlerItem, hook ...string
|
||||
switch handler.itemType {
|
||||
// 判断是否已存在相同的路由注册项,如果是普通路由注册则进行替换
|
||||
case gHANDLER_TYPE_HANDLER, gHANDLER_TYPE_OBJECT, gHANDLER_TYPE_CONTROLLER:
|
||||
if handler.itemType == gHANDLER_TYPE_HANDLER {
|
||||
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 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
|
||||
}
|
||||
fallthrough
|
||||
|
||||
// 否则,那么判断优先级,决定插入顺序
|
||||
default:
|
||||
@ -183,8 +176,7 @@ func (s *Server) setHandler(pattern string, handler *handlerItem, hook ...string
|
||||
l.PushBack(handler)
|
||||
}
|
||||
}
|
||||
// gutil.Dump(s.serveTree)
|
||||
// gutil.Dump(s.hooksTree)
|
||||
//gutil.Dump(s.serveTree)
|
||||
if _, ok := s.routesMap[regkey]; !ok {
|
||||
s.routesMap[regkey] = make([]registeredRouteItem, 0)
|
||||
}
|
||||
|
@ -7,12 +7,8 @@
|
||||
package ghttp
|
||||
|
||||
import (
|
||||
"container/list"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/gogf/gf/text/gregex"
|
||||
)
|
||||
|
||||
// 绑定指定的hook回调函数, pattern参数同BindHandler,支持命名路由;hook参数的值由ghttp server设定,参数不区分大小写
|
||||
@ -21,6 +17,7 @@ func (s *Server) BindHookHandler(pattern string, hook string, handler HandlerFun
|
||||
itemType: gHANDLER_TYPE_HOOK,
|
||||
itemName: runtime.FuncForPC(reflect.ValueOf(handler).Pointer()).Name(),
|
||||
itemFunc: handler,
|
||||
hookName: hook,
|
||||
}, hook)
|
||||
}
|
||||
|
||||
@ -34,11 +31,7 @@ func (s *Server) BindHookHandlerByMap(pattern string, hookmap map[string]Handler
|
||||
// 事件回调处理,内部使用了缓存处理.
|
||||
// 并按照指定hook回调函数的优先级及注册顺序进行调用
|
||||
func (s *Server) callHookHandler(hook string, r *Request) {
|
||||
// 如果没有hook注册,那么不用执行后续逻辑
|
||||
if len(s.hooksTree) == 0 {
|
||||
return
|
||||
}
|
||||
hookItems := s.getHookHandlerWithCache(hook, r)
|
||||
hookItems := r.getHookHandlers(hook)
|
||||
if len(hookItems) > 0 {
|
||||
// 备份原有的router变量
|
||||
oldRouterVars := r.routerVars
|
||||
@ -86,111 +79,6 @@ func (s *Server) niceCallHookHandler(f HandlerFunc, r *Request) (err interface{}
|
||||
return
|
||||
}
|
||||
|
||||
// 查询请求处理方法, 带缓存机制,按照Host、Method、Path进行缓存.
|
||||
func (s *Server) getHookHandlerWithCache(hook string, r *Request) []*handlerParsedItem {
|
||||
cacheItems := ([]*handlerParsedItem)(nil)
|
||||
cacheKey := s.handlerKey(hook, r.Method, r.URL.Path, r.GetHost())
|
||||
if v := s.hooksCache.Get(cacheKey); v == nil {
|
||||
cacheItems = s.searchHookHandler(r.Method, r.URL.Path, r.GetHost(), hook)
|
||||
if cacheItems != nil {
|
||||
s.hooksCache.Set(cacheKey, cacheItems, s.config.RouterCacheExpire*1000)
|
||||
}
|
||||
} else {
|
||||
cacheItems = v.([]*handlerParsedItem)
|
||||
}
|
||||
return cacheItems
|
||||
}
|
||||
|
||||
// 事件方法检索
|
||||
func (s *Server) searchHookHandler(method, path, domain, hook string) []*handlerParsedItem {
|
||||
if len(path) == 0 {
|
||||
return nil
|
||||
}
|
||||
// 遍历检索的域名列表
|
||||
domains := []string{gDEFAULT_DOMAIN}
|
||||
if !strings.EqualFold(gDEFAULT_DOMAIN, domain) {
|
||||
domains = append(domains, domain)
|
||||
}
|
||||
// URL.Path层级拆分
|
||||
array := ([]string)(nil)
|
||||
if strings.EqualFold("/", path) {
|
||||
array = []string{"/"}
|
||||
} else {
|
||||
array = strings.Split(path[1:], "/")
|
||||
}
|
||||
parsedItems := make([]*handlerParsedItem, 0, 8)
|
||||
for _, domain := range domains {
|
||||
p, ok := s.hooksTree[domain]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
p, ok = p.(map[string]interface{})[hook]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
// 多层链表(每个节点都有一个*list链表)的目的是当叶子节点未有任何规则匹配时,让父级模糊匹配规则继续处理
|
||||
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 {
|
||||
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))
|
||||
break
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if _, ok := p.(map[string]interface{})["*fuzz"]; ok {
|
||||
p = p.(map[string]interface{})["*fuzz"]
|
||||
}
|
||||
}
|
||||
// 如果是叶子节点,同时判断当前层级的"*fuzz"键名,解决例如:/user/*action 匹配 /user 的规则
|
||||
if k == len(array)-1 {
|
||||
if _, ok := p.(map[string]interface{})["*fuzz"]; ok {
|
||||
p = p.(map[string]interface{})["*fuzz"]
|
||||
}
|
||||
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() {
|
||||
handler := e.Value.(*handlerItem)
|
||||
// 动态匹配规则带有gDEFAULT_METHOD的情况,不会像静态规则那样直接解析为所有的HTTP METHOD存储
|
||||
if strings.EqualFold(handler.router.Method, gDEFAULT_METHOD) || strings.EqualFold(handler.router.Method, method) {
|
||||
// 注意当不带任何动态路由规则时,len(match) == 1
|
||||
if match, err := gregex.MatchString(handler.router.RegRule, path); err == nil && len(match) > 0 {
|
||||
parsedItem := &handlerParsedItem{handler, nil}
|
||||
// 如果需要query匹配,那么需要重新正则解析URL
|
||||
if len(handler.router.RegNames) > 0 {
|
||||
if len(match) > len(handler.router.RegNames) {
|
||||
parsedItem.values = make(map[string][]string)
|
||||
// 如果存在存在同名路由参数名称,那么执行数组追加
|
||||
for i, name := range handler.router.RegNames {
|
||||
if _, ok := parsedItem.values[name]; ok {
|
||||
parsedItem.values[name] = append(parsedItem.values[name], match[i+1])
|
||||
} else {
|
||||
parsedItem.values[name] = []string{match[i+1]}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
parsedItems = append(parsedItems, parsedItem)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return parsedItems
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 生成hook key,如果是hook key,那么使用'%'符号分隔
|
||||
func (s *Server) handlerKey(hook, method, path, domain string) string {
|
||||
return hook + "%" + s.serveHandlerKey(method, path, domain)
|
||||
|
@ -7,35 +7,40 @@
|
||||
package ghttp
|
||||
|
||||
import (
|
||||
"container/list"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/gogf/gf/container/glist"
|
||||
"github.com/gogf/gf/text/gregex"
|
||||
)
|
||||
|
||||
// 缓存数据项
|
||||
type handlerCacheItem struct {
|
||||
parsedItems []*handlerParsedItem
|
||||
hasHook bool
|
||||
}
|
||||
|
||||
// 查询请求处理方法.
|
||||
// 内部带锁机制,可以并发读,但是不能并发写;并且有缓存机制,按照Host、Method、Path进行缓存.
|
||||
func (s *Server) getHandlersWithCache(r *Request) []*handlerParsedItem {
|
||||
func (s *Server) getHandlersWithCache(r *Request) (parsedItems []*handlerParsedItem, hasHook bool) {
|
||||
cacheKey := s.serveHandlerKey(r.Method, r.URL.Path, r.GetHost())
|
||||
cacheItems := ([]*handlerParsedItem)(nil)
|
||||
if v := s.serveCache.Get(cacheKey); v == nil {
|
||||
cacheItems = s.searchHandlers(r.Method, r.URL.Path, r.GetHost())
|
||||
if cacheItems != nil {
|
||||
s.serveCache.Set(cacheKey, cacheItems, s.config.RouterCacheExpire*1000)
|
||||
parsedItems, hasHook = s.searchHandlers(r.Method, r.URL.Path, r.GetHost())
|
||||
if parsedItems != nil {
|
||||
s.serveCache.Set(cacheKey, &handlerCacheItem{parsedItems, hasHook}, s.config.RouterCacheExpire*1000)
|
||||
}
|
||||
} else {
|
||||
cacheItems = v.([]*handlerParsedItem)
|
||||
item := v.(*handlerCacheItem)
|
||||
return item.parsedItems, item.hasHook
|
||||
}
|
||||
if len(cacheItems) == 0 {
|
||||
return nil
|
||||
}
|
||||
return cacheItems
|
||||
return
|
||||
}
|
||||
|
||||
// 路由注册方法检索,返回所有该路由的注册函数,构造成数组返回
|
||||
func (s *Server) searchHandlers(method, path, domain string) []*handlerParsedItem {
|
||||
func (s *Server) searchHandlers(method, path, domain string) (parsedItems []*handlerParsedItem, hasHook bool) {
|
||||
if len(path) == 0 {
|
||||
return nil
|
||||
return nil, false
|
||||
}
|
||||
// 遍历检索的域名列表,优先遍历默认域名
|
||||
domains := []string{gDEFAULT_DOMAIN}
|
||||
@ -49,24 +54,25 @@ func (s *Server) searchHandlers(method, path, domain string) []*handlerParsedIte
|
||||
} else {
|
||||
array = strings.Split(path[1:], "/")
|
||||
}
|
||||
parsedItems := make([]*handlerParsedItem, 0, 16)
|
||||
parsedItems = make([]*handlerParsedItem, 0, 16)
|
||||
isServeHandlerAdded := false
|
||||
for _, domain := range domains {
|
||||
p, ok := s.serveTree[domain]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
//gutil.Dump(p)
|
||||
// 多层链表(每个节点都有一个*list链表)的目的是当叶子节点未有任何规则匹配时,让父级模糊匹配规则继续处理
|
||||
lists := make([]*list.List, 0, 16)
|
||||
lists := make([]*glist.List, 0, 16)
|
||||
for k, v := range array {
|
||||
if _, ok := p.(map[string]interface{})["*list"]; ok {
|
||||
lists = append(lists, p.(map[string]interface{})["*list"].(*list.List))
|
||||
lists = append(lists, p.(map[string]interface{})["*list"].(*glist.List))
|
||||
}
|
||||
if _, ok := p.(map[string]interface{})[v]; ok {
|
||||
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))
|
||||
lists = append(lists, p.(map[string]interface{})["*list"].(*glist.List))
|
||||
break
|
||||
}
|
||||
}
|
||||
@ -81,7 +87,7 @@ func (s *Server) searchHandlers(method, path, domain string) []*handlerParsedIte
|
||||
p = p.(map[string]interface{})["*fuzz"]
|
||||
}
|
||||
if _, ok := p.(map[string]interface{})["*list"]; ok {
|
||||
lists = append(lists, p.(map[string]interface{})["*list"].(*list.List))
|
||||
lists = append(lists, p.(map[string]interface{})["*list"].(*glist.List))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -124,12 +130,38 @@ func (s *Server) searchHandlers(method, path, domain string) []*handlerParsedIte
|
||||
isServeHandlerAdded = true
|
||||
}
|
||||
}
|
||||
if item.itemType == gHANDLER_TYPE_HOOK {
|
||||
hasHook = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return parsedItems
|
||||
return
|
||||
}
|
||||
|
||||
// MarshalJSON implements the interface MarshalJSON for json.Marshal.
|
||||
func (item *handlerItem) MarshalJSON() ([]byte, error) {
|
||||
if item.hookName != "" {
|
||||
return json.Marshal(
|
||||
fmt.Sprintf(
|
||||
`%s %s:%s (%s)`,
|
||||
item.router.Uri,
|
||||
item.router.Domain,
|
||||
item.router.Method,
|
||||
item.hookName,
|
||||
),
|
||||
)
|
||||
}
|
||||
return json.Marshal(
|
||||
fmt.Sprintf(
|
||||
`%s %s:%s`,
|
||||
item.router.Uri,
|
||||
item.router.Domain,
|
||||
item.router.Method,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
// 生成回调方法查询的Key
|
||||
|
@ -23,18 +23,18 @@ func Test_Router_Basic(t *testing.T) {
|
||||
s.BindHandler("/:name", func(r *ghttp.Request) {
|
||||
r.Response.Write("/:name")
|
||||
})
|
||||
//s.BindHandler("/:name/update", func(r *ghttp.Request) {
|
||||
// r.Response.Write(r.Get("name"))
|
||||
//})
|
||||
//s.BindHandler("/:name/:action", func(r *ghttp.Request) {
|
||||
// r.Response.Write(r.Get("action"))
|
||||
//})
|
||||
s.BindHandler("/:name/update", func(r *ghttp.Request) {
|
||||
r.Response.Write(r.Get("name"))
|
||||
})
|
||||
s.BindHandler("/:name/:action", func(r *ghttp.Request) {
|
||||
r.Response.Write(r.Get("action"))
|
||||
})
|
||||
s.BindHandler("/:name/*any", func(r *ghttp.Request) {
|
||||
r.Response.Write(r.Get("any"))
|
||||
})
|
||||
//s.BindHandler("/user/list/{field}.html", func(r *ghttp.Request) {
|
||||
// r.Response.Write(r.Get("field"))
|
||||
//})
|
||||
s.BindHandler("/user/list/{field}.html", func(r *ghttp.Request) {
|
||||
r.Response.Write(r.Get("field"))
|
||||
})
|
||||
s.SetPort(p)
|
||||
s.SetDumpRouteMap(false)
|
||||
s.Start()
|
||||
|
@ -24,8 +24,6 @@ func Test_Router_Hook_Basic(t *testing.T) {
|
||||
"AfterServe": func(r *ghttp.Request) { r.Response.Write("2") },
|
||||
"BeforeOutput": func(r *ghttp.Request) { r.Response.Write("3") },
|
||||
"AfterOutput": func(r *ghttp.Request) { r.Response.Write("4") },
|
||||
"BeforeClose": func(r *ghttp.Request) { r.Response.Write("5") },
|
||||
"AfterClose": func(r *ghttp.Request) { r.Response.Write("6") },
|
||||
})
|
||||
s.BindHandler("/test/test", func(r *ghttp.Request) {
|
||||
r.Response.Write("test")
|
||||
|
Loading…
Reference in New Issue
Block a user