ghttp路由功能改进

This commit is contained in:
John
2018-04-11 12:05:25 +08:00
parent 213e0e25f1
commit e4656cdc51
6 changed files with 136 additions and 35 deletions

View File

@ -19,6 +19,7 @@ import (
"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"
)
const (
@ -150,32 +151,18 @@ func (s *Server) setHandler(domain, method, pattern string, item HandlerItem) {
}
// 查询请求处理方法
func (s *Server) getHandler(domain, method, pattern string) *HandlerItem {
s.hmu.RLock()
defer s.hmu.RUnlock()
key := s.handlerKey(domain, method, pattern)
if f, ok := s.handlerMap[key]; ok {
return &f
}
return nil
}
// 解析pattern
func (s *Server)parsePattern(pattern string) (domain, method, uri string, err error) {
uri = ""
func (s *Server)parsePatternForBindHandler(pattern string) (domain, method, uri string, err error) {
uri = pattern
domain = gDEFAULT_DOMAIN
method = "all"
result := strings.Split(pattern, "@")
if len(result) > 1 {
domain = result[1]
if array, err := gregx.MatchString(`([a-zA-Z]+):(.+)`, pattern); len(array) > 1 && err == nil {
method = array[1]
pattern = array[2]
}
result = strings.Split(result[0], ":")
if len(result) > 1 {
method = result[0]
uri = result[1]
} else {
uri = result[0]
if array, err := gregx.MatchString(`(.+)@([\w\.\-]+)`, pattern); len(array) > 1 && err == nil {
uri = array[1]
domain = array[2]
}
if uri == "" {
err = errors.New("invalid pattern")
@ -190,7 +177,7 @@ func (s *Server)bindHandlerItem(pattern string, item HandlerItem) error {
if s.status == 1 {
return errors.New("server handlers cannot be changed while running")
}
domain, method, uri, err := s.parsePattern(pattern)
domain, method, uri, err := s.parsePatternForBindHandler(pattern)
if err != nil {
return errors.New("invalid pattern")
}
@ -346,7 +333,7 @@ func (s *Server)BindControllerMethod(pattern string, c Controller, methods strin
// 绑定指定的hook回调函数, hook参数的值由ghttp server设定参数不区分大小写
// 目前hook支持Init/Shut
func (s *Server)BindHookHandler(pattern string, hook string, handler HandlerFunc) error {
domain, method, uri, err := s.parsePattern(pattern)
domain, method, uri, err := s.parsePatternForBindHandler(pattern)
if err != nil {
return errors.New("invalid pattern")
}

View File

@ -19,6 +19,8 @@ import (
"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"
)
// 默认HTTP Server处理入口http包底层默认使用了gorutine异步处理请求所以这里不再异步执行
@ -31,7 +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 {
@ -47,15 +49,78 @@ func (s *Server)handleRequest(w http.ResponseWriter, r *http.Request) {
ResponseWriter : w,
},
}
if h := s.getHandler(gDEFAULT_DOMAIN, r.Method, r.URL.Path); h != nil {
if h := s.getHandler(request); h != nil {
s.callHandler(h, request)
} else {
if h := s.getHandler(strings.Split(r.Host, ":")[0], r.Method, r.URL.Path); h != nil {
s.callHandler(h, request)
} else {
s.serveFile(w, r)
s.serveFile(w, r)
}
}
// 查询请求处理方法
func (s *Server) getHandler(r *Request) *HandlerItem {
s.hmu.RLock()
defer s.hmu.RUnlock()
domains := []string{gDEFAULT_DOMAIN, strings.Split(r.Host, ":")[0]}
// 首先进行静态匹配
for _, domain := range domains {
if f, ok := s.handlerMap[s.handlerKey(domain, r.Method, r.URL.Path)]; ok {
return &f
}
}
// 其次进行正则匹配(会比较耗效率)
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)
}
}
return &v
}
}
}
}
}
return nil
}
// 将pattern不带method和domain解析成正则表达式匹配以及对应的query字符串
func (s *Server) patternToRegRule(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
}
// 初始化控制器

View File

@ -25,8 +25,8 @@ type Router struct {
pmu sync.RWMutex // 打包规则互斥锁
dkeys []string // 解析规则排序键名
pkeys []string // 打包规则排序键名
drules *gmap.StringStringMap // 解析规则
prules *gmap.StringStringMap // 打包规则
drules *gmap.StringStringMap // dispatch解析规则
prules *gmap.StringStringMap // patch打包规则
}
func New() *Router {

View File

@ -11,6 +11,12 @@ import (
"regexp"
)
// 校验所给定的正则表达式是否符合规范
func Validate(pattern string) error {
_, err := regexp.Compile(pattern)
return err
}
// 正则表达式是否匹配
func IsMatch(pattern string, src []byte) bool {
match, err := regexp.Match(pattern, src)

11
geg/net/ghttp/router.go Normal file
View File

@ -0,0 +1,11 @@
package main
import "gitee.com/johng/gf/g/net/ghttp"
func main () {
ghttp.GetServer().BindHandler("/router/:name", func(r *ghttp.Request) {
r.Response.WriteString(r.GetQueryString("name"))
})
ghttp.GetServer().SetPort(10000)
ghttp.GetServer().Run()
}

View File

@ -1,10 +1,42 @@
package main
import (
"gitee.com/johng/gf/g/os/glog"
"strings"
"fmt"
"gitee.com/johng/gf/g/util/gregx"
"strconv"
)
func main() {
glog.Println(1)
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")))
}