mirror of
https://gitee.com/johng/gf
synced 2026-06-28 10:16:09 +08:00
ghttp路由功能改进
This commit is contained in:
@ -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")
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
// 初始化控制器
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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
11
geg/net/ghttp/router.go
Normal 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()
|
||||
}
|
||||
@ -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")))
|
||||
}
|
||||
Reference in New Issue
Block a user