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  }