mirror of
https://gitee.com/johng/gf
synced 2026-06-06 16:21:40 +08:00
ghttp路由优先级改进
This commit is contained in:
@ -34,10 +34,12 @@ func (this *IntBoolMap) Clone() *map[int]bool {
|
||||
}
|
||||
|
||||
// 给定回调函数对原始内容进行遍历
|
||||
func (this *IntBoolMap) Iterator(f func (k int, v bool)) {
|
||||
func (this *IntBoolMap) Iterator(f func (k int, v bool) bool) {
|
||||
this.mu.RLock()
|
||||
for k, v := range this.m {
|
||||
f(k, v)
|
||||
if !f(k, v) {
|
||||
break
|
||||
}
|
||||
}
|
||||
this.mu.RUnlock()
|
||||
}
|
||||
|
||||
@ -23,10 +23,12 @@ func NewIntIntMap() *IntIntMap {
|
||||
}
|
||||
|
||||
// 给定回调函数对原始内容进行遍历
|
||||
func (this *IntIntMap) Iterator(f func (k int, v int)) {
|
||||
func (this *IntIntMap) Iterator(f func (k int, v int) bool) {
|
||||
this.mu.RLock()
|
||||
for k, v := range this.m {
|
||||
f(k, v)
|
||||
if !f(k, v) {
|
||||
break
|
||||
}
|
||||
}
|
||||
this.mu.RUnlock()
|
||||
}
|
||||
|
||||
@ -24,10 +24,12 @@ func NewIntInterfaceMap() *IntInterfaceMap {
|
||||
}
|
||||
|
||||
// 给定回调函数对原始内容进行遍历
|
||||
func (this *IntInterfaceMap) Iterator(f func (k int, v interface{})) {
|
||||
func (this *IntInterfaceMap) Iterator(f func (k int, v interface{}) bool) {
|
||||
this.mu.RLock()
|
||||
for k, v := range this.m {
|
||||
f(k, v)
|
||||
if !f(k, v) {
|
||||
break
|
||||
}
|
||||
}
|
||||
this.mu.RUnlock()
|
||||
}
|
||||
|
||||
@ -23,10 +23,12 @@ func NewIntStringMap() *IntStringMap {
|
||||
}
|
||||
|
||||
// 给定回调函数对原始内容进行遍历
|
||||
func (this *IntStringMap) Iterator(f func (k int, v string)) {
|
||||
func (this *IntStringMap) Iterator(f func (k int, v string) bool) {
|
||||
this.mu.RLock()
|
||||
for k, v := range this.m {
|
||||
f(k, v)
|
||||
if !f(k, v) {
|
||||
break
|
||||
}
|
||||
}
|
||||
this.mu.RUnlock()
|
||||
}
|
||||
|
||||
@ -24,10 +24,12 @@ func NewInterfaceInterfaceMap() *InterfaceInterfaceMap {
|
||||
}
|
||||
|
||||
// 给定回调函数对原始内容进行遍历
|
||||
func (this *InterfaceInterfaceMap) Iterator(f func (k interface{}, v interface{})) {
|
||||
func (this *InterfaceInterfaceMap) Iterator(f func (k interface{}, v interface{}) bool) {
|
||||
this.mu.RLock()
|
||||
for k, v := range this.m {
|
||||
f(k, v)
|
||||
if !f(k, v) {
|
||||
break
|
||||
}
|
||||
}
|
||||
this.mu.RUnlock()
|
||||
}
|
||||
|
||||
@ -23,10 +23,12 @@ func NewStringBoolMap() *StringBoolMap {
|
||||
}
|
||||
|
||||
// 给定回调函数对原始内容进行遍历
|
||||
func (this *StringBoolMap) Iterator(f func (k string, v bool)) {
|
||||
func (this *StringBoolMap) Iterator(f func (k string, v bool) bool) {
|
||||
this.mu.RLock()
|
||||
for k, v := range this.m {
|
||||
f(k, v)
|
||||
if !f(k, v) {
|
||||
break
|
||||
}
|
||||
}
|
||||
this.mu.RUnlock()
|
||||
}
|
||||
|
||||
@ -23,10 +23,12 @@ func NewStringIntMap() *StringIntMap {
|
||||
}
|
||||
|
||||
// 给定回调函数对原始内容进行遍历
|
||||
func (this *StringIntMap) Iterator(f func (k string, v int)) {
|
||||
func (this *StringIntMap) Iterator(f func (k string, v int) bool) {
|
||||
this.mu.RLock()
|
||||
for k, v := range this.m {
|
||||
f(k, v)
|
||||
if !f(k, v) {
|
||||
break
|
||||
}
|
||||
}
|
||||
this.mu.RUnlock()
|
||||
}
|
||||
|
||||
@ -24,10 +24,12 @@ func NewStringInterfaceMap() *StringInterfaceMap {
|
||||
}
|
||||
|
||||
// 给定回调函数对原始内容进行遍历
|
||||
func (this *StringInterfaceMap) Iterator(f func (k string, v interface{})) {
|
||||
func (this *StringInterfaceMap) Iterator(f func (k string, v interface{}) bool) {
|
||||
this.mu.RLock()
|
||||
for k, v := range this.m {
|
||||
f(k, v)
|
||||
if !f(k, v) {
|
||||
break
|
||||
}
|
||||
}
|
||||
this.mu.RUnlock()
|
||||
}
|
||||
|
||||
@ -23,10 +23,12 @@ func NewStringStringMap() *StringStringMap {
|
||||
}
|
||||
|
||||
// 给定回调函数对原始内容进行遍历
|
||||
func (this *StringStringMap) Iterator(f func (k string, v string)) {
|
||||
func (this *StringStringMap) Iterator(f func (k string, v string) bool) {
|
||||
this.mu.RLock()
|
||||
for k, v := range this.m {
|
||||
f(k, v)
|
||||
if !f(k, v) {
|
||||
break
|
||||
}
|
||||
}
|
||||
this.mu.RUnlock()
|
||||
}
|
||||
|
||||
@ -23,10 +23,12 @@ func NewUintInterfaceMap() *UintInterfaceMap {
|
||||
}
|
||||
}
|
||||
|
||||
func (this *UintInterfaceMap) Iterator(f func (k uint, v interface{})) {
|
||||
func (this *UintInterfaceMap) Iterator(f func (k uint, v interface{}) bool) {
|
||||
this.mu.RLock()
|
||||
for k, v := range this.m {
|
||||
f(k, v)
|
||||
if !f(k, v) {
|
||||
break
|
||||
}
|
||||
}
|
||||
this.mu.RUnlock()
|
||||
}
|
||||
|
||||
@ -23,10 +23,12 @@ func NewIntSet() *IntSet {
|
||||
}
|
||||
|
||||
// 给定回调函数对原始内容进行遍历
|
||||
func (this *IntSet) Iterator(f func (v int)) {
|
||||
func (this *IntSet) Iterator(f func (v int) bool) {
|
||||
this.mu.RLock()
|
||||
for k, _ := range this.m {
|
||||
f(k)
|
||||
if !f(k) {
|
||||
break
|
||||
}
|
||||
}
|
||||
this.mu.RUnlock()
|
||||
}
|
||||
|
||||
@ -22,10 +22,12 @@ func NewInterfaceSet() *InterfaceSet {
|
||||
}
|
||||
|
||||
// 给定回调函数对原始内容进行遍历
|
||||
func (this *InterfaceSet) Iterator(f func (v interface{})) {
|
||||
func (this *InterfaceSet) Iterator(f func (v interface{}) bool) {
|
||||
this.mu.RLock()
|
||||
for k, _ := range this.m {
|
||||
f(k)
|
||||
if !f(k) {
|
||||
break
|
||||
}
|
||||
}
|
||||
this.mu.RUnlock()
|
||||
}
|
||||
|
||||
@ -22,10 +22,12 @@ func NewStringSet() *StringSet {
|
||||
}
|
||||
|
||||
// 给定回调函数对原始内容进行遍历
|
||||
func (this *StringSet) Iterator(f func (v string)) {
|
||||
func (this *StringSet) Iterator(f func (v string) bool) {
|
||||
this.mu.RLock()
|
||||
for k, _ := range this.m {
|
||||
f(k)
|
||||
if !f(k) {
|
||||
break
|
||||
}
|
||||
}
|
||||
this.mu.RUnlock()
|
||||
}
|
||||
|
||||
@ -22,10 +22,12 @@ func NewUintSet() *UintSet {
|
||||
}
|
||||
|
||||
// 给定回调函数对原始内容进行遍历
|
||||
func (this *UintSet) Iterator(f func (v uint)) {
|
||||
func (this *UintSet) Iterator(f func (v uint) bool) {
|
||||
this.mu.RLock()
|
||||
for k, _ := range this.m {
|
||||
f(k)
|
||||
if !f(k) {
|
||||
break
|
||||
}
|
||||
}
|
||||
this.mu.RUnlock()
|
||||
}
|
||||
|
||||
@ -9,7 +9,6 @@ package ghttp
|
||||
import (
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"gitee.com/johng/gf/g/util/gconv"
|
||||
"gitee.com/johng/gf/g/encoding/gjson"
|
||||
"gitee.com/johng/gf/g/container/gtype"
|
||||
@ -18,20 +17,42 @@ import (
|
||||
// 请求对象
|
||||
type Request struct {
|
||||
http.Request
|
||||
parsedPost *gtype.Bool // POST参数是否已经解析
|
||||
getvals *url.Values // GET参数
|
||||
Id int // 请求id(唯一)
|
||||
Server *Server // 请求关联的服务器对象
|
||||
Cookie *Cookie // 与当前请求绑定的Cookie对象(并发安全)
|
||||
Session *Session // 与当前请求绑定的Session对象(并发安全)
|
||||
Response *Response // 对应请求的返回数据操作对象
|
||||
parsedGet *gtype.Bool // GET参数是否已经解析
|
||||
parsedPost *gtype.Bool // POST参数是否已经解析
|
||||
values map[string][]string // GET参数
|
||||
Id int // 请求id(唯一)
|
||||
Server *Server // 请求关联的服务器对象
|
||||
Cookie *Cookie // 与当前请求绑定的Cookie对象(并发安全)
|
||||
Session *Session // 与当前请求绑定的Session对象(并发安全)
|
||||
Response *Response // 对应请求的返回数据操作对象
|
||||
}
|
||||
|
||||
// 创建一个Request对象
|
||||
func newRequest(s *Server, r *http.Request, w http.ResponseWriter) *Request {
|
||||
return &Request{
|
||||
parsedGet : gtype.NewBool(),
|
||||
parsedPost : gtype.NewBool(),
|
||||
values : make(map[string][]string),
|
||||
Id : s.servedCount.Add(1),
|
||||
Server : s,
|
||||
Request : *r,
|
||||
Response : &Response {
|
||||
ResponseWriter : w,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 初始化GET请求参数
|
||||
func (r *Request) initGet() {
|
||||
if r.getvals == nil {
|
||||
values := r.URL.Query()
|
||||
r.getvals = &values
|
||||
if !r.parsedGet.Val() {
|
||||
if len(r.values) == 0 {
|
||||
r.values = r.URL.Query()
|
||||
} else {
|
||||
for k, v := range r.URL.Query() {
|
||||
r.values[k] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -48,7 +69,7 @@ func (r *Request) initPost() {
|
||||
// 获得指定名称的get参数列表
|
||||
func (r *Request) GetQuery(k string) []string {
|
||||
r.initGet()
|
||||
if v, ok := (*r.getvals)[k]; ok {
|
||||
if v, ok := r.values[k]; ok {
|
||||
return v
|
||||
}
|
||||
return nil
|
||||
@ -92,7 +113,7 @@ func (r *Request) GetQueryMap(defaultMap...map[string]string) map[string]string
|
||||
r.initGet()
|
||||
m := make(map[string]string)
|
||||
if len(defaultMap) == 0 {
|
||||
for k, v := range *r.getvals {
|
||||
for k, v := range r.values {
|
||||
m[k] = v[0]
|
||||
}
|
||||
} else {
|
||||
|
||||
@ -12,18 +12,17 @@ import (
|
||||
"strings"
|
||||
"reflect"
|
||||
"net/http"
|
||||
"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"
|
||||
"gitee.com/johng/gf/g/util/gregx"
|
||||
"gitee.com/johng/gf/g/util/gutil"
|
||||
"gitee.com/johng/gf/g/container/gmap"
|
||||
"gitee.com/johng/gf/g/container/glist"
|
||||
"gitee.com/johng/gf/g/container/gtype"
|
||||
"gitee.com/johng/gf/g/container/gqueue"
|
||||
)
|
||||
|
||||
const (
|
||||
gHTTP_METHODS = "GET,PUT,POST,DELETE,PATCH,HEAD,CONNECT,OPTIONS,TRACE"
|
||||
gHTTP_METHODS = "GET,POST,DELETE,PUT,PATCH,HEAD,CONNECT,OPTIONS,TRACE"
|
||||
gDEFAULT_SERVER = "default"
|
||||
gDEFAULT_DOMAIN = "default"
|
||||
gDEFAULT_METHOD = "all"
|
||||
@ -49,10 +48,9 @@ type Server struct {
|
||||
cookieMaxAge *gtype.Int // Cookie有效期
|
||||
sessionMaxAge *gtype.Int // Session有效期
|
||||
sessionIdName *gtype.String // SessionId名称
|
||||
routers *gcache.Cache // 服务注册路由内存缓存
|
||||
cookies *gmap.IntInterfaceMap // 当前服务器正在服务(请求正在执行)的Cookie(每个请求一个Cookie对象)
|
||||
sessions *gcache.Cache // Session内存缓存
|
||||
|
||||
Router *grouter.Router // 路由管理对象
|
||||
}
|
||||
|
||||
// 域名、URI与回调函数的绑定记录表
|
||||
@ -81,14 +79,14 @@ func GetServer(names...string) (*Server) {
|
||||
if s := serverMapping.Get(name); s != nil {
|
||||
return s.(*Server)
|
||||
}
|
||||
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(),
|
||||
routers : gcache.New(),
|
||||
cookies : gmap.NewIntInterfaceMap(),
|
||||
sessions : gcache.New(),
|
||||
cookieMaxAge : gtype.NewInt(gDEFAULT_COOKIE_MAX_AGE),
|
||||
@ -103,7 +101,7 @@ func GetServer(names...string) (*Server) {
|
||||
return s
|
||||
}
|
||||
|
||||
// 执行
|
||||
// 阻塞执行监听
|
||||
func (s *Server) Run() error {
|
||||
if s.status == 1 {
|
||||
return errors.New("server is already running")
|
||||
@ -137,7 +135,7 @@ func (s *Server) handlerKey(domain, method, pattern string) string {
|
||||
return strings.ToUpper(method) + ":" + pattern + "@" + strings.ToLower(domain)
|
||||
}
|
||||
|
||||
// 设置请求处理方法
|
||||
// 注册服务处理方法
|
||||
func (s *Server) setHandler(domain, method, pattern string, item HandlerItem) {
|
||||
s.hmu.Lock()
|
||||
defer s.hmu.Unlock()
|
||||
@ -330,8 +328,7 @@ func (s *Server)BindControllerMethod(pattern string, c Controller, methods strin
|
||||
return s.bindHandlerByMap(m)
|
||||
}
|
||||
|
||||
// 绑定指定的hook回调函数, hook参数的值由ghttp server设定,参数不区分大小写
|
||||
// 目前hook支持:Init/Shut
|
||||
// 绑定指定的hook回调函数, pattern参数同BindHandler,支持命名路由;hook参数的值由ghttp server设定,参数不区分大小写
|
||||
func (s *Server)BindHookHandler(pattern string, hook string, handler HandlerFunc) error {
|
||||
domain, method, uri, err := s.parsePatternForBindHandler(pattern)
|
||||
if err != nil {
|
||||
@ -364,32 +361,7 @@ func (s *Server)BindHookHandlerByMap(pattern string, hookmap map[string]HandlerF
|
||||
return nil
|
||||
}
|
||||
|
||||
//// 绑定URI服务注册的Init回调函数,回调时按照注册顺序执行
|
||||
//// Init回调调用时机为请求进入控制器之前,初始化Request对象之后
|
||||
//func (s *Server)BindHookHandlerInit(pattern string, handler HandlerFunc) error {
|
||||
// return s.BindHookHandler(pattern, "Init", handler)
|
||||
//}
|
||||
//
|
||||
//// 绑定URI服务注册的Shut回调函数,回调时按照注册顺序执行
|
||||
//// Shut回调调用时机为请求执行完成之后,所有的请求资源释放之前
|
||||
//func (s *Server)BindHookHandlerShut(pattern string, handler HandlerFunc) error {
|
||||
// return s.BindHookHandler(pattern, "Shut", handler)
|
||||
//}
|
||||
|
||||
// 构造用于hooksMap检索的键名
|
||||
func (s *Server)handlerHookKey(domain, method, uri, hook string) string {
|
||||
return strings.ToUpper(hook) + "^" + s.handlerKey(domain, method, uri)
|
||||
}
|
||||
|
||||
// 获取指定hook的回调函数列表,按照注册顺序排序
|
||||
func (s *Server)getHookList(domain, method, uri, hook string) []HandlerFunc {
|
||||
if v := s.hooksMap.Get(s.handlerHookKey(domain, method, uri, hook)); v != nil {
|
||||
items := v.(*glist.List).FrontAll()
|
||||
funcs := make([]HandlerFunc, len(items))
|
||||
for k, v := range items {
|
||||
funcs[k] = v.(HandlerFunc)
|
||||
}
|
||||
return funcs
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -128,25 +128,3 @@ func (d *Domain)BindHookHandlerByMap(pattern string, hookmap map[string]HandlerF
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
//// 绑定URI服务注册的Init回调函数,回调时按照注册顺序执行
|
||||
//// Init回调调用时机为请求进入控制器之前,初始化Request对象之后
|
||||
//func (d *Domain)BindHookHandlerInit(pattern string, handler HandlerFunc) error {
|
||||
// for domain, _ := range d.m {
|
||||
// if err := d.s.BindHookHandlerInit(pattern + "@" + domain, handler); err != nil {
|
||||
// return err
|
||||
// }
|
||||
// }
|
||||
// return nil
|
||||
//}
|
||||
//
|
||||
//// 绑定URI服务注册的Shut回调函数,回调时按照注册顺序执行
|
||||
//// Shut回调调用时机为请求执行完成之后,所有的请求资源释放之前
|
||||
//func (d *Domain)BindHookHandlerShut(pattern string, handler HandlerFunc) error {
|
||||
// for domain, _ := range d.m {
|
||||
// if err := d.s.BindHookHandlerShut(pattern + "@" + domain, handler); err != nil {
|
||||
// return err
|
||||
// }
|
||||
// }
|
||||
// return nil
|
||||
//}
|
||||
@ -13,14 +13,14 @@ import (
|
||||
"sort"
|
||||
"reflect"
|
||||
"strings"
|
||||
"strconv"
|
||||
"net/url"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
"gitee.com/johng/gf/g/os/gfile"
|
||||
"gitee.com/johng/gf/g/encoding/ghtml"
|
||||
"gitee.com/johng/gf/g/container/gtype"
|
||||
"gitee.com/johng/gf/g/util/gregx"
|
||||
"strconv"
|
||||
"gitee.com/johng/gf/g/encoding/ghtml"
|
||||
"gitee.com/johng/gf/g/container/glist"
|
||||
)
|
||||
|
||||
// 默认HTTP Server处理入口,http包底层默认使用了gorutine异步处理请求,所以这里不再异步执行
|
||||
@ -33,22 +33,7 @@ func (s *Server)defaultHttpHandle(w http.ResponseWriter, r *http.Request) {
|
||||
// 其次,如果没有对应的自定义处理接口配置,那么走默认的域名处理接口配置;
|
||||
// 最后,如果以上都没有找到处理接口,那么进行文件处理;
|
||||
func (s *Server)handleRequest(w http.ResponseWriter, r *http.Request) {
|
||||
// 全局路由解析
|
||||
uri := r.URL.String()
|
||||
result, err := s.Router.Dispatch(uri)
|
||||
if err == nil && strings.Compare(uri, result) != 0 {
|
||||
r.URL, _ = r.URL.Parse(result)
|
||||
}
|
||||
// 构造请求参数对象
|
||||
request := &Request{
|
||||
parsedPost : gtype.NewBool(),
|
||||
Id : s.servedCount.Add(1),
|
||||
Server : s,
|
||||
Request : *r,
|
||||
Response : &Response {
|
||||
ResponseWriter : w,
|
||||
},
|
||||
}
|
||||
request := newRequest(s, r, w)
|
||||
if h := s.getHandler(request); h != nil {
|
||||
s.callHandler(h, request)
|
||||
} else {
|
||||
@ -57,7 +42,14 @@ func (s *Server)handleRequest(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
// 查询请求处理方法
|
||||
// 这里有个锁机制,可以并发读,但是不能并发写
|
||||
func (s *Server) getHandler(r *Request) *HandlerItem {
|
||||
handler := s.searchHandler(r)
|
||||
return handler
|
||||
}
|
||||
|
||||
// 服务方法检索
|
||||
func (s *Server) searchHandler(r *Request) *HandlerItem {
|
||||
s.hmu.RLock()
|
||||
defer s.hmu.RUnlock()
|
||||
domains := []string{gDEFAULT_DOMAIN, strings.Split(r.Host, ":")[0]}
|
||||
@ -71,23 +63,28 @@ func (s *Server) getHandler(r *Request) *HandlerItem {
|
||||
for k, v := range s.handlerMap {
|
||||
if array, err := gregx.MatchString(`([a-zA-Z]+):(.+)@([\w\.\-]+)`, k); len(array) > 2 && err == nil {
|
||||
// method匹配
|
||||
if strings.EqualFold(r.Method, array[1]) {
|
||||
for _, domain := range domains {
|
||||
// domain匹配
|
||||
if !strings.EqualFold(domain, array[3]) {
|
||||
continue
|
||||
}
|
||||
// method & domain匹配时,那么执行pattern的正则匹配
|
||||
regrule, querystr := s.patternToRegRule(array[2])
|
||||
if gregx.IsMatchString(regrule, r.URL.Path) {
|
||||
// 如果需要query匹配,那么需要重新解析URL
|
||||
if len(querystr) > 0 {
|
||||
if result, err := gregx.ReplaceString(regrule, querystr, r.URL.Path); err == nil {
|
||||
r.URL, _ = r.URL.Parse(r.URL.Path + "?" + r.URL.RawQuery + "&" + result)
|
||||
if !strings.EqualFold(r.Method, array[1]) {
|
||||
continue
|
||||
}
|
||||
// domain匹配
|
||||
for _, domain := range domains {
|
||||
if !strings.EqualFold(domain, array[3]) {
|
||||
continue
|
||||
}
|
||||
// method & domain匹配时,那么执行pattern的正则匹配
|
||||
regrule, querystr := s.patternToRegRule(array[2])
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
return &v
|
||||
}
|
||||
return &v
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -95,29 +92,103 @@ func (s *Server) getHandler(r *Request) *HandlerItem {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
// 按照指定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
|
||||
}
|
||||
|
||||
// 将pattern(不带method和domain)解析成正则表达式匹配以及对应的query字符串
|
||||
func (s *Server) patternToRegRule(rule string) (regrule string, querystr string) {
|
||||
regrule = "/"
|
||||
if len(rule) < 2 {
|
||||
return rule, ""
|
||||
}
|
||||
regrule = "^/"
|
||||
array := strings.Split(rule[1:], "/")
|
||||
index := 1
|
||||
for _, v := range array {
|
||||
switch v[0] {
|
||||
case ':':
|
||||
regrule += `/([\w\.\-]+)`
|
||||
if len(querystr) > 0 {
|
||||
querystr += "&"
|
||||
}
|
||||
querystr += v[1:] + "=$" + strconv.Itoa(index)
|
||||
index++
|
||||
case '*':
|
||||
regrule += `/(.*)`
|
||||
if len(querystr) > 0 {
|
||||
querystr += "&"
|
||||
}
|
||||
querystr += v[1:] + "=$" + strconv.Itoa(index)
|
||||
return
|
||||
default:
|
||||
regrule += v
|
||||
case ':':
|
||||
regrule += `/([\w\.\-]+)`
|
||||
if len(querystr) > 0 {
|
||||
querystr += "&"
|
||||
}
|
||||
querystr += v[1:] + "=$" + strconv.Itoa(index)
|
||||
index++
|
||||
case '*':
|
||||
regrule += `/(.*)`
|
||||
if len(querystr) > 0 {
|
||||
querystr += "&"
|
||||
}
|
||||
querystr += v[1:] + "=$" + strconv.Itoa(index)
|
||||
return
|
||||
default:
|
||||
regrule += v
|
||||
}
|
||||
}
|
||||
return
|
||||
@ -142,14 +213,6 @@ func (s *Server)callHandler(h *HandlerItem, r *Request) {
|
||||
}
|
||||
s.callHookHandler(r, "AfterServe")
|
||||
|
||||
// 路由规则打包
|
||||
s.callHookHandler(r, "BeforePatch")
|
||||
if buffer, err := s.Router.Patch(r.Response.Buffer()); err == nil {
|
||||
r.Response.ClearBuffer()
|
||||
r.Response.Write(buffer)
|
||||
}
|
||||
s.callHookHandler(r, "AfterPatch")
|
||||
|
||||
s.callHookHandler(r, "BeforeOutput")
|
||||
|
||||
// 输出Cookie
|
||||
@ -163,20 +226,6 @@ func (s *Server)callHandler(h *HandlerItem, r *Request) {
|
||||
s.closeQueue.PushBack(r)
|
||||
}
|
||||
|
||||
// 按照指定hook回调函数的注册顺序进行调用
|
||||
func (s *Server)callHookHandler(r *Request, hook string) {
|
||||
l := s.getHookList(gDEFAULT_DOMAIN, r.Method, r.URL.Path, hook)
|
||||
if l == nil {
|
||||
l = s.getHookList(strings.Split(r.Host, ":")[0], r.Method, r.URL.Path, hook)
|
||||
}
|
||||
if l == nil {
|
||||
return
|
||||
}
|
||||
for _, f := range l {
|
||||
f(r)
|
||||
}
|
||||
}
|
||||
|
||||
// 处理静态文件请求
|
||||
func (s *Server)serveFile(w http.ResponseWriter, r *http.Request) {
|
||||
uri := r.URL.String()
|
||||
|
||||
@ -1,120 +0,0 @@
|
||||
// Copyright 2017 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 grouter
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"bytes"
|
||||
"errors"
|
||||
"strings"
|
||||
"gitee.com/johng/gf/g/util/gregx"
|
||||
"gitee.com/johng/gf/g/container/gmap"
|
||||
"gitee.com/johng/gf/g/util/gutil"
|
||||
)
|
||||
|
||||
// 路由管理对象
|
||||
type Router struct {
|
||||
dmu sync.RWMutex // 解析规则互斥锁
|
||||
pmu sync.RWMutex // 打包规则互斥锁
|
||||
dkeys []string // 解析规则排序键名
|
||||
pkeys []string // 打包规则排序键名
|
||||
drules *gmap.StringStringMap // dispatch解析规则
|
||||
prules *gmap.StringStringMap // patch打包规则
|
||||
}
|
||||
|
||||
func New() *Router {
|
||||
return &Router{
|
||||
drules : gmap.NewStringStringMap(),
|
||||
prules : gmap.NewStringStringMap(),
|
||||
}
|
||||
}
|
||||
|
||||
// 设置解析规则,例如:静态分页
|
||||
// `\/([\w\.\-]+)\/([\w\.\-]+)\/page\/([\d\.\-]+)[\/\?]*`, "/user/list/page/2"
|
||||
func (r *Router) SetRule(rule, replace string) {
|
||||
r.drules.Set(rule, replace)
|
||||
if !gutil.StringInArray(r.dkeys, rule) {
|
||||
r.dmu.Lock()
|
||||
r.dkeys = append(r.dkeys, rule)
|
||||
r.dmu.Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
// 删除解析规则
|
||||
func (r *Router) RemoveRule(rule string) {
|
||||
if i := gutil.StringSearch(r.dkeys, rule); i != -1 {
|
||||
r.drules.Remove(rule)
|
||||
r.dmu.Lock()
|
||||
r.dkeys = append(r.dkeys[ : i], r.dkeys[i + 1 : ]...)
|
||||
r.dmu.Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
// 设置打包规则
|
||||
func (r *Router) SetPatchRule(rule, replace string) {
|
||||
r.prules.Set(rule, replace)
|
||||
if !gutil.StringInArray(r.pkeys, rule) {
|
||||
r.pmu.Lock()
|
||||
r.pkeys = append(r.pkeys, rule)
|
||||
r.pmu.Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
// 删除打包规则
|
||||
func (r *Router) RemovePatchRule(rule string) {
|
||||
if i := gutil.StringSearch(r.pkeys, rule); i != -1 {
|
||||
r.prules.Remove(rule)
|
||||
r.pmu.Lock()
|
||||
r.pkeys = append(r.pkeys[ : i], r.pkeys[i + 1 : ]...)
|
||||
r.pmu.Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
// 解析URI
|
||||
func (r *Router) Dispatch(uri string) (string, error) {
|
||||
r.dmu.RLock()
|
||||
defer r.dmu.RUnlock()
|
||||
if len(r.dkeys) == 0 {
|
||||
return uri, errors.New("no dispatch rules found")
|
||||
}
|
||||
for _, rule := range r.dkeys {
|
||||
if replace := r.drules.Get(rule); replace != "" {
|
||||
result, err := gregx.ReplaceString(rule, replace, uri)
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
if len(uri) != len(result) || strings.Compare(result, uri) != 0 {
|
||||
return result, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return uri, nil
|
||||
}
|
||||
|
||||
// 打包内容
|
||||
func (r *Router) Patch(content []byte) ([]byte, error) {
|
||||
r.pmu.RLock()
|
||||
defer r.pmu.RUnlock()
|
||||
if len(r.pkeys) == 0 {
|
||||
return content, errors.New("no patch rules found")
|
||||
}
|
||||
for _, rule := range r.pkeys {
|
||||
if replace := r.prules.Get(rule); replace != "" {
|
||||
result, err := gregx.Replace(rule, []byte(replace), content)
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
if len(content) != len(result) || bytes.Compare(result, content) != 0 {
|
||||
return result, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return content, nil
|
||||
}
|
||||
@ -334,7 +334,7 @@ func (c *Cache) autoClearLoop() {
|
||||
}
|
||||
|
||||
// 删除对应键名的缓存数据
|
||||
func (c *Cache) clearByKey(key string) {
|
||||
func (c *Cache) clearByKey(key string) bool {
|
||||
// 删除缓存数据
|
||||
c.dmu.Lock()
|
||||
delete(c.data, key)
|
||||
@ -347,4 +347,6 @@ func (c *Cache) clearByKey(key string) {
|
||||
|
||||
// 删除LRU管理对象中指定键名
|
||||
c.lru.Remove(key)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
@ -3,7 +3,7 @@ package main
|
||||
import "gitee.com/johng/gf/g/net/ghttp"
|
||||
|
||||
func main () {
|
||||
ghttp.GetServer().BindHandler("/router/:name", func(r *ghttp.Request) {
|
||||
ghttp.GetServer().BindHandler("/router/*name", func(r *ghttp.Request) {
|
||||
r.Response.WriteString(r.GetQueryString("name"))
|
||||
})
|
||||
ghttp.GetServer().SetPort(10000)
|
||||
|
||||
@ -1,42 +1,16 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"fmt"
|
||||
"gitee.com/johng/gf/g/util/gregx"
|
||||
"strconv"
|
||||
"gitee.com/johng/gf/g/os/gtime"
|
||||
)
|
||||
|
||||
func ruleToRegx(rule string) (regrule string, querystr string) {
|
||||
regrule = "/"
|
||||
array := strings.Split(rule[1:], "/")
|
||||
index := 1
|
||||
for _, v := range array {
|
||||
switch v[0] {
|
||||
case ':':
|
||||
regrule += `/([\w\.\-]+)`
|
||||
if len(querystr) > 0 {
|
||||
querystr += "&"
|
||||
}
|
||||
querystr += v[1:] + "=$" + strconv.Itoa(index)
|
||||
index++
|
||||
case '*':
|
||||
regrule += `/(.*)`
|
||||
if len(querystr) > 0 {
|
||||
querystr += "&"
|
||||
}
|
||||
querystr += v[1:] + "=$" + strconv.Itoa(index)
|
||||
return
|
||||
default:
|
||||
regrule += v
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func main() {
|
||||
fmt.Println(strings.Compare("A", "A"))
|
||||
fmt.Println(gregx.MatchString(`(\w+):(.+)@([\w\.\-]+)`, "get/users/name/*action@www.johng-cn.com"))
|
||||
fmt.Println(ruleToRegx("/users/:name/*action"))
|
||||
fmt.Println(gregx.IsMatch(`/users/([\w\.\-]+)/(.*)`, []byte("/users/john/aa/aa/aa")))
|
||||
t1 := gtime.Microsecond()
|
||||
for i := 0; i < 10000; i++ {
|
||||
gregx.MatchString(`([a-zA-Z]+)\^([a-zA-Z]+):(.+)@([\w\.\-]+)`, "a^b:c@d")
|
||||
}
|
||||
t2 := gtime.Microsecond()
|
||||
fmt.Println(t2 - t1)
|
||||
}
|
||||
Reference in New Issue
Block a user