畅远数码|万字手撕Go http源码server.go( 三 )
func appendSorted(es []muxEntry, e muxEntry) []muxEntry {n := len(es)i := sort.Search(n, func(i int) bool {return len(es[i].pattern) < len(e.pattern)})if i == n {return append(es, e)}// we now know that i points at where we want to insertes = append(es, muxEntry{}) // try to grow the slice in place, any entry works.copy(es[i+1:], es[i:])// Move shorter entries downes[i] = ereturn es}复制代码mux.HandleFunc()
mux.HandleFunc()是我认为最重要的一个方法 , 同样是将handler注册到路由表中 , 我们应该对比mux.HandleFunc()和mux.Handle()的区别 , 其实从函数体来看mux.HandleFunc()算是对mux.Handle()函数的一个再封装 , 调用了HandlerFunc()这个适配器函数 , 本质上是将一个普通函数作为HTTP请求handler的语法糖 , 我们不再需要实现ServeHTTP()方法 , 取而代之的是传入的普通函数只要为func(ResponseWriter, *Request)类型的 , 就可以进行函数的路由 , 基本上一行代码就可以搞定 , 这也是为什么在官网示例中我们可以轻而易举的构建简单的web程序的原因 。 在官网示例的HandleFunc()函数中调用了默认复用器的DefaultServeMux.HandleFunc()方法 , 开发者只需要自己定义普通函数即可:
// HandleFunc registers the handler function for the given pattern.func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {if handler == nil {panic("http: nil handler")}mux.Handle(pattern, HandlerFunc(handler))}复制代码私有方法mux.match()
当调用mux.Handler()返回Handler类时在mux.handler()内部会调用mux.match()函数 , 本质上可以看作是路由查找的过程(Handle()是路由注册的过程)
// Find a handler on a handler map given a path string.// Most-specific (longest) pattern wins.func (mux *ServeMux) match(path string) (h Handler, pattern string) {// Check for exact match first.v, ok := mux.m[path]if ok {return v.h, v.pattern}// Check for longest valid match.mux.es contains all patterns// that end in / sorted from longest to shortest.for _, e := range mux.es {if strings.HasPrefix(path, e.pattern) {return e.h, e.pattern}}return nil, ""}复制代码在进行匹配的过程中:
1.首先在路由表中进行精确匹配 , 匹配到muxEntry后返回
2.如果在路由表中没有查询到 , 则在有序数组es中进行匹配 , 从strings.HasPrefix()可以看出 , 本质上这是一种模糊匹配 , 只匹配了相应的前缀 , 就认定匹配成功
3.如果相应前缀无法查询 , 则认为匹配失败 , 返回nil handler
总结匹配规则一句话描述是: Longer patterns take precedence over shorter ones , 长字符串模式优先级大于短字符串模式 , 优先匹配长字符串
mux.shouldRedirectRLocked()
mux.shouldRedirectRLocked()方法的作用较为简单 , 判断是否需要对像"/tree/"这种路由的重定向(在ServeMux中对于"/tree"会自动重定向到"/tree/" , 除非路由表中已有"/tree" , 此过程在mux.Handler()中调用mux.redirectToPathSlash()完成)
1.判断路由表中是否存在host+path或者path的组合 , 如果存在则不需要重定向
2.如果path为空字符串 , 则不需要重定向
3.如果当前路由表中存在path+“/” , 则需要重定向(例如在注册时将"/tree/"注册到表中 , 则对于"/tree"的路由重定向到了"/tree/" , )
func (mux *ServeMux) shouldRedirectRLocked(host, path string) bool {p := []string{path, host + path}for _, c := range p {if _, exist := mux.m[c]; exist {return false}}n := len(path)if n == 0 {return false}for _, c := range p {if _, exist := mux.m[c+"/"]; exist {return path[n-1] != '/'}}return false}复制代码
推荐阅读
- 英雄科技聊数码|蔡崇信有实力买下篮网,那身价3200亿的马云,能买下几支NBA球队
- 搜狐新闻|准大学生数码三件套如何选?这些元气好物值得种草
- 数码鲜蜂|三星大秀肌肉!这个透明手机如何?
- 数码科技大爆炸|台积电断供华为芯片开启倒计时!已不足10天:华为多位高管表态
- 海外网|菅义伟计划对厚生劳动省进行改革 创设"数码厅"
- 数码实验室|《飞速骑行4》2021年推出PS5和XboxSeriesX版
- 老实人数码|取代苹果XR系列,不支持5G网络,iPhone12s真机疑似被曝光
- 畅远数码|马云曾提出的4大预言,已经实现3个,网友:最后一个才是关键
- 神说要唱歌|数码宝贝大冒号14话解读 虫王对决 偷学战斗龙卷风的超比多兽
- 畅远数码|欧洲大量5G基站被烧毁!原因让人啼笑皆非
