ghttp路由优先级改进

This commit is contained in:
John
2018-04-11 16:06:45 +08:00
parent 3bb3d27009
commit b0dc9064e0
22 changed files with 234 additions and 330 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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