github.com/zhongdalu/gf@v1.0.0/g/net/ghttp/ghttp_server_router_serve.go (about) 1 // Copyright 2018 gf Author(https://github.com/zhongdalu/gf). All Rights Reserved. 2 // 3 // This Source Code Form is subject to the terms of the MIT License. 4 // If a copy of the MIT was not distributed with this file, 5 // You can obtain one at https://github.com/zhongdalu/gf. 6 // 服务注册路由控制. 7 8 package ghttp 9 10 import ( 11 "container/list" 12 "strings" 13 14 "github.com/zhongdalu/gf/g/text/gregex" 15 ) 16 17 // 查询请求处理方法. 18 // 内部带锁机制,可以并发读,但是不能并发写;并且有缓存机制,按照Host、Method、Path进行缓存. 19 func (s *Server) getServeHandlerWithCache(r *Request) *handlerParsedItem { 20 cacheItem := (*handlerParsedItem)(nil) 21 cacheKey := s.serveHandlerKey(r.Method, r.URL.Path, r.GetHost()) 22 if v := s.serveCache.Get(cacheKey); v == nil { 23 cacheItem = s.searchServeHandler(r.Method, r.URL.Path, r.GetHost()) 24 if cacheItem != nil { 25 s.serveCache.Set(cacheKey, cacheItem, s.config.RouterCacheExpire*1000) 26 } 27 } else { 28 cacheItem = v.(*handlerParsedItem) 29 } 30 return cacheItem 31 } 32 33 // 服务方法检索 34 func (s *Server) searchServeHandler(method, path, domain string) *handlerParsedItem { 35 if len(path) == 0 { 36 return nil 37 } 38 // 遍历检索的域名列表 39 domains := []string{gDEFAULT_DOMAIN} 40 if !strings.EqualFold(gDEFAULT_DOMAIN, domain) { 41 domains = append(domains, domain) 42 } 43 // URL.Path层级拆分 44 array := ([]string)(nil) 45 if strings.EqualFold("/", path) { 46 array = []string{"/"} 47 } else { 48 array = strings.Split(path[1:], "/") 49 } 50 for _, domain := range domains { 51 p, ok := s.serveTree[domain] 52 if !ok { 53 continue 54 } 55 // 多层链表(每个节点都有一个*list链表)的目的是当叶子节点未有任何规则匹配时,让父级模糊匹配规则继续处理 56 lists := make([]*list.List, 0) 57 for k, v := range array { 58 if _, ok := p.(map[string]interface{})["*list"]; ok { 59 lists = append(lists, p.(map[string]interface{})["*list"].(*list.List)) 60 } 61 if _, ok := p.(map[string]interface{})[v]; ok { 62 p = p.(map[string]interface{})[v] 63 if k == len(array)-1 { 64 if _, ok := p.(map[string]interface{})["*list"]; ok { 65 lists = append(lists, p.(map[string]interface{})["*list"].(*list.List)) 66 break 67 } 68 } 69 } else { 70 if _, ok := p.(map[string]interface{})["*fuzz"]; ok { 71 p = p.(map[string]interface{})["*fuzz"] 72 } 73 } 74 // 如果是叶子节点,同时判断当前层级的"*fuzz"键名,解决例如:/user/*action 匹配 /user 的规则 75 if k == len(array)-1 { 76 if _, ok := p.(map[string]interface{})["*fuzz"]; ok { 77 p = p.(map[string]interface{})["*fuzz"] 78 } 79 if _, ok := p.(map[string]interface{})["*list"]; ok { 80 lists = append(lists, p.(map[string]interface{})["*list"].(*list.List)) 81 } 82 } 83 } 84 85 // 多层链表遍历检索,从数组末尾的链表开始遍历,末尾的深度高优先级也高 86 for i := len(lists) - 1; i >= 0; i-- { 87 for e := lists[i].Front(); e != nil; e = e.Next() { 88 item := e.Value.(*handlerItem) 89 // 动态匹配规则带有gDEFAULT_METHOD的情况,不会像静态规则那样直接解析为所有的HTTP METHOD存储 90 if strings.EqualFold(item.router.Method, gDEFAULT_METHOD) || strings.EqualFold(item.router.Method, method) { 91 // 注意当不带任何动态路由规则时,len(match) == 1 92 if match, err := gregex.MatchString(item.router.RegRule, path); err == nil && len(match) > 0 { 93 //gutil.Dump(match) 94 //gutil.Dump(names) 95 parsedItem := &handlerParsedItem{item, nil} 96 // 如果需要query匹配,那么需要重新正则解析URL 97 if len(item.router.RegNames) > 0 { 98 if len(match) > len(item.router.RegNames) { 99 parsedItem.values = make(map[string][]string) 100 // 如果存在存在同名路由参数名称,那么执行数组追加 101 for i, name := range item.router.RegNames { 102 if _, ok := parsedItem.values[name]; ok { 103 parsedItem.values[name] = append(parsedItem.values[name], match[i+1]) 104 } else { 105 parsedItem.values[name] = []string{match[i+1]} 106 } 107 } 108 } 109 } 110 return parsedItem 111 } 112 } 113 } 114 } 115 } 116 return nil 117 } 118 119 // 生成回调方法查询的Key 120 func (s *Server) serveHandlerKey(method, path, domain string) string { 121 if method == "" { 122 return path + "@" + strings.ToLower(domain) 123 } 124 return strings.ToUpper(method) + ":" + path + "@" + strings.ToLower(domain) 125 }