go从0到1项目实战体系五十一:httprouter库源码分析二

3. httprouter路由原理:

. 路由器依赖于大量使用通用前缀的树结构,是一个紧凑的前缀树(或只是基数树).. 具有公共前缀的节点也共享一个公共的父节点.

(1). 举例 - Get树:

. 路由:
   router := httprouter.New()
   router.GET("/search/", func1)
   router.GET("/support/", func2)
   router.GET("/blog/:post/", func3)
   router.GET("/about-us/", func4)
   router.GET("/about-us/team/", func5)
   router.GET("/contact/", func6). GET请求方法的路由树:
   Priority     Path                   Handle
   9            \                      *<1>
   3            ├─ s                   nil           
   2            |  ├─ earch\           *<2>
   1            |  ├─ upport\          *<3>
   2            ├─ blog\               *<4>
   1            |  ├─ :post            nil
   1            |     ├─ \             *<5>
   2            ├─ about-us\           *<6>
   1            |     ├─ team\         *<7>
   1            ├─ contact\            *<8>. priority优先级:
	 a. 层次越深,优先级priority越高.
	 b. 为了保证有序.. 前缀树:
	 a. 定义的路径是有限的,就可以按照字母的顺序做一个前缀树.
	 b. search和support有相同的s前缀,这就是前缀树.
	 c. s是没有处理函数的,所以是nil

⑤. blog/:post中:
   a. :post是实际文章名称的占位符(参数).
   b. 与hash-maps不同,这种树结构还允许使用像:post参数这种动态部分.
	 c. 实际上是根据路由模式进行匹配,而不仅仅是比较哈希值.. Handle:
	 a. 表示前缀树节点对应的Handle处理函数(指针)的内存地址.
	 b. 沿着树从根到叶的路径走,可以得到完整的路径.

(2). 前缀树的优点:

. 处理每一个请求路径,:"about-us".. 从前缀树从上向下匹配:
	 a. s不符合,往下.
	 b. blog不符合,往下.
	 c. about-us符合:
			(1). 查看后面没有,正好匹配,找到Handle为*<b>对应的函数.
			(2). 否则,继续匹配.. 其实就是字符串匹配.. 层次结构:
   a. 由于URL路径具有层次结构.
	 b. 只使⽤有限的⼀组字符(字节值),可能会有许多常⻅的前缀.
	 c. 路由器为每个请求⽅法管理⼀个单独的树.
	 d. 它⽐在每个节点中保存⼀个⽅法(>句柄映射)更节省空间.

(3). 优先级是什么?

. 考虑到可伸缩性,每个树级别上的子节点都按Priority(优先级)排序.
   |---------
	 |--------
	 |-----
	 |--
	 |-
	 a. 当一个url,下面挂载的Handler越多,就优先去匹配它.
	 b. 值越大,说明大部分路由都在这个节点上,命中率会很高.
   c. 这是一种成本补偿,最长可达路径(最高成本)总是可以先求值.
		  (1). 如果最上面那个节点url占用了80%.
			(2). 从下往上匹配的话,就会有80%的url从下面向上匹配,做无用功.
			(3). 反之,如果是从上往下匹配,下面的请求也是只有几%的在做无用功.. 优先级就是子节点(子节点、子子节点等等)中所有注册的句柄的数量.. 源码中:
	 a. 从上到下,从左到右计算节点的函数:addRoute、insertChild
	 b. 匹配路由函数:getValue

(4). 为什么层级越深的,优先级越高?

. 寻找的方案:
   a. 字符串匹配
	 b. hash maps:根据key找值、速度快
	 
②. 为什么不用hash maps?
   a. 因为url是一种有限的字符串集合.
	 b. hash的路由无法匹配包含blog\:post这种路由:
	    (1). :post只是文章名称的占位符(参数).
			(2). :post是可变的、动态的任意参数.
	 c. 实际上是根据路由模式进行匹配,并不仅仅是比较哈希值.
	 d. hash maps格式比较固定.

4. 源码中使用_是什么作用?

// Make sure the Router conforms with the http.Handler interface
var _ http.Handler = New()

// New returns a new initialized Router.
// Path auto-correction, including trailing slashes, is enabled by default.
func New() *Router {
	return &Router{
		RedirectTrailingSlash:  true,
		RedirectFixedPath:      true,
		HandleMethodNotAllowed: true,
		HandleOPTIONS:          true,
	}
}

(1). 说明:

. http.Handler是一个接口.. var _ http.Handler = New()
	 a. var表示声明
	 b. _表示变量名
	 c. http.Handler表示类型
	 d. New()返回的是一个结构体指针

③. 作用:
   a. 确保接口实现,确保变量满足了接口实现,并非自动初始化.
   b. 相当于
      var a http.Handler   // 声明了一个变量,类型是http.Handler
      a = New()            // 赋值
	 c. 什么情况下,可以把这个New()的结构体指针赋值给a?
	    (1). 是不是只有当这个结构体实现了接口的所有方法的时候,表示这个结构体满足了这个接口.
			(2). 就能把这个结构体变量直接赋值给接口变量,即a.
   d. 这样做的,目的是确保New函数返回的结构体是可以满足http.Handler.
	 e. 但是这样写,a是没有使用的.所以,使用_来代替.
  • 6
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值