畅远数码|万字手撕Go http源码server.go( 二 )
结构体内黑盒 , 包含已过滤和未导出的字段 , 其实就是不想让你知道里面的构造 , 事实上的构造如下:
type ServeMux struct {musync.RWMutex// 读写互斥锁mmap[string]muxEntry// 路由表es[]muxEntry// 有序数组 , 从最长到最短排序hosts bool// whether any patterns contain hostnames}复制代码ServeMux结构体本质上是由mu读写互斥锁、m路由表、es数组(很多老教程都没有这个更新字段)和hosts布尔值组成
其中:
1.mu是读写互斥锁 , 详情见设计思想
2.m是路由表 , 路由表本质上就是一个map[string]muxEntry变量 , 键是路径字符串(由method和传入参数拼接字符串组成) , 值是对应的处理结构体muxEntry
3.es是一个有序数组 , 由长到短维护所有后缀为/的路由地址 , 至于为什么要这样设计 , 见设计思想
4.布尔类型的hosts属性标记路由中是否带有主机名 , 若hosts值为true , 则路由的起始不能为/
m路由表中的muxEntry的结构体如下:
type muxEntry struct {hHandler // 处理程序patternstring// 路由路径}复制代码muxEntry本质上是由Handler类和路由路径字符串组成 , 其中:
1.h是Handler类型 , Handler类型要求实现接口中的ServeHTTP方法
2.pattern实际上和路由表中的key相同
默认多路复用器在net/http包中规定了默认的多路复用器 , 如果不自己手写指定则使用默认mux:
// DefaultServeMux is the default ServeMux used by Serve.var DefaultServeMux =ok {return RedirectHandler(u.String(), StatusMovedPermanently), u.Path}return mux.handler(r.Host, r.URL.Path)}// All other requests have any port stripped and path cleaned// before passing to mux.handler.host := stripHostPort(r.Host)path := cleanPath(r.URL.Path)// If the given path is /tree and its handler is not registered,// redirect for /tree/.if u, ok := mux.redirectToPathSlash(host, path, r.URL); ok {return RedirectHandler(u.String(), StatusMovedPermanently), u.Path}if path != r.URL.Path {_, pattern = mux.handler(host, path)url := *r.URLurl.Path = pathreturn RedirectHandler(url.String(), StatusMovedPermanently), pattern}return mux.handler(host, r.URL.Path)}复制代码对于r.host和r.URL.Path进行了简单处理 , 简要说明一下两个函数cleanPath()和stripHostPort()分别做了什么工作:
cleanPath()
1.处理无效路由
2.对于斜杠的处理 , 代替无效的多个斜杠
3.移除所有的.替换为等效path
简单来说就是对路径进行处理为等效最短路径 , 使之可以在后续查找路由表的过程中可以查找到相应键值对 。
// cleanPath returns the canonical path for p, eliminating . and .. elements.func cleanPath(p string) string {if p == "" {return "/"}if p[0] != '/' {p = "/" + p}np := path.Clean(p)// path.Clean removes trailing slash except for root;// put the trailing slash back if necessary.if p[len(p)-1] == '/'exist {panic("http: multiple registrations for " + pattern)}if mux.m == nil {mux.m = make(map[string]muxEntry)}e := muxEntry{h: handler, pattern: pattern}mux.m[pattern] = eif pattern[len(pattern)-1] == '/' {mux.es = appendSorted(mux.es, e)}if pattern[0] != '/' {mux.hosts = true}}复制代码对于路由在表中重复会引发panic , 对于后缀为slash/的路径 , 按照长度大小写入mux.es中 , 之前分析结构体mux时也提到过这一点 。
简单看一下其实现的排序函数:
推荐阅读
- 英雄科技聊数码|蔡崇信有实力买下篮网,那身价3200亿的马云,能买下几支NBA球队
- 搜狐新闻|准大学生数码三件套如何选?这些元气好物值得种草
- 数码鲜蜂|三星大秀肌肉!这个透明手机如何?
- 数码科技大爆炸|台积电断供华为芯片开启倒计时!已不足10天:华为多位高管表态
- 海外网|菅义伟计划对厚生劳动省进行改革 创设"数码厅"
- 数码实验室|《飞速骑行4》2021年推出PS5和XboxSeriesX版
- 老实人数码|取代苹果XR系列,不支持5G网络,iPhone12s真机疑似被曝光
- 畅远数码|马云曾提出的4大预言,已经实现3个,网友:最后一个才是关键
- 神说要唱歌|数码宝贝大冒号14话解读 虫王对决 偷学战斗龙卷风的超比多兽
- 畅远数码|欧洲大量5G基站被烧毁!原因让人啼笑皆非
