设为首页 收藏本站
查看: 1538|回复: 0

[经验分享] golang中ServeMux解析

[复制链接]

尚未签到

发表于 2018-9-20 06:53:00 | 显示全部楼层 |阅读模式
ServeMux解析


  • 总览
  • ServeMux结构体
  • NewServeMux
  • pathMatch
  • * ServeMux.Handler
  • * ServeMux.handler
  • * ServeMux.Handle
  • * ServeMux.ServeHTTP
总览
  本来是想做一个UML出来让这篇解析更清晰一点的,但是markdown的UML语法我一直捣鼓不出来。试了几个软件感觉也没有
  
想象中的好用和方便,看来是时候自己开发一个了(笑).
  
口述一个流程,具体的函数大家可以页内跳转去看.
  
首先我们是通过ListenAndServe来监听本地端口的,之后ListenAndServe将收到的新建一个Response连同收到的Request
  
作为参数调用ServeMux结构体的ServeHTTP(省略了中间过程).ServeHTTP将Request作为参数调用
  
Handler函数,Handler的返回值为一个Handler类型的接口,ServeHTTP会调用接口实现的ServeHTTP处理Response.
  如果Request.URL.Path中有不合法的内容,则调用cleanPath清理,随后将Request.Host以及清理后的
  
内容传入handler函数,随后返回一个RedirectHandler以及handler所返回的路径。如果Request.URL.Path合法,那么
  
直接调用handler,返回值与handler返回值相同。
  handler中通过判断ServeMux.hosts来决定是否实现pattern = r.Host + r.URL.Path.之后将pattern作为参数调用match,并将
  
match的返回值返回.
  match的判别方式比较"有趣",它虽然没实现为树形结构(只是用了映射),但是搜索的方法就是树形,因为URL路径就是个树形.它按照树的根节点
  
与子节点的关系进行判断,譬如路径"/home/select/usercourse",match在匹配的时候会首先匹配到"/"(假如我们注册了),其次是"/home",
  
之后逐层匹配下来,假如我们没注册过"/home/select/usercourse",但是注册了"/home/select/",那么match就会匹配到这一层.然后返回
  
"/home/select/"的Handler以及url(pattern).match函数的匹配规则实现在pathMatch

ServeMux结构体
  

type ServeMux struct {  mu    sync.RWMutex
  m     map[string]muxEntry
  hosts bool // whether any patterns contain hostnames
  }
  

  
type muxEntry struct {
  explicit bool
  h        Handler
  pattern  string
  }
  

  这样看起来还蛮直观的,mu是一个互斥锁,m则是我们所要用的路由(router),其中的键(key)则是我们挂载的路径,
  
对应的值则是响应的muxEntry,hosts指明了我们是否在每个路径中都声明了hostnames.比如我们平常用'/'来表示
  
挂载在域名根目录下的HandlerFunc,但是如果hosts=true,那么我们就需要'127.0.0.1/'来做同样的事情了.
  下面我们来看muxEntry,h比较明确,就是我们注册的处理过程.pattern与ServeMux中m的key相同,也就是说是我们
  
注册的路径,而explicit的用途其实是比较隐晦的。程序会根据explicit判别这个路径的Handler是否是用户注册的。
  
如果是程序为了Redirect(详细点击这里)而设定的,那么在它是可以被覆盖的,否则就是不可以被覆盖的.

NewServeMux()
  DefaultServeMux变量就是直接调用的这个函数。那么这个函数只make了一个变量m,也就是为map分配了空间。
  
在golang的语法中,结构体里未声明的变量也是存在的(即分配了内存),只不过是该类型的默认值,比如hosts就
  
被设置成了false.这个问题不过多解释,有兴趣的话可以看一下golang中的相关内容

pathMatch()
  这个函数是ServeMux用来匹配路径的主要函数,所以看一下策略还是很重要的.
  
函数中的参数pattern是我们注册的路径,path是用户请求的路径
  

func pathMatch(pattern, path string) bool {  if len(pattern) == 0 {
  // should not happen
  return false
  }
  n := len(pattern)
  if pattern[n-1] != '/' {
  return pattern == path
  }
  return len(path) >= n && path[0:n] == pattern
  
}
  

  如果我们挂载的路径不是以'/'结尾的,那么就直接判断两个参数是否相同。如果是以'/'结尾的,只要path的路径包含
  
pattern那么就被判定是匹配。也就是说,如果我注册了/home/select/,那么/home/select/hello也会被定位到/home/select/
  
挂载的HandlerFunc上.这样做相当于为路径设置了一个index,不符合规则的URL都会被Redirect到这个index上

* ServeMux.Handler()
  注释写的很清楚,这个函数就是处理URL,然后调用*ServeMux.handler().首先调用cleanPath清理请求URL中的不合法内容。如果存在不合法内容,
  
则将清理过的URL交由*ServeMux.handler()处理并获得匹配到的pattern,然后修改url.Path的内容并调用RedirectHandler.
  
如果内容合法,则直接调用*ServeMux.handler()并返回结果

* ServeMux.handler()
  调用ServeMux.match()(封装了pathMatch函数)来获得匹配到的Handler以及对应pattern,如果ServeMux.hosts==true,那么
  
传入的参数为host + path,如果找不到的话,调用NotFoundHandler函数,并将其结果返回.

* ServeMux.Handle()
  Handle函数是用来注册路径与处理过程的.如果该路径已经存在了一个用户注册的Handler则会panic(意思就是说不支持覆盖).判别了合法参数以后就将
  
pattern作为key,新建一个muxEntry类型变量作为value加入到map中。
  

if pattern[0] != '/' {  mux.hosts = true
  
}
  

  这是这个函数中比较有意思的一个部分,通过这里我们可以看到如果注册路径的时候并不是以'/'开头的,那么ServeMux就会开启hosts,然后会在
  
请求到达的时候将URL.Host和URL.Path连接在一起放入match中寻找,具体信息请看这里
  接下来是关于路径的处理,也就是关于"/home"与"/home/"的区别.我们先来看看作者怎么说
  

    // Helpful behavior:  // If pattern is /tree/, insert an implicit permanent redirect for /tree.
  // It can be overridden by an explicit registration.
  

  如果路径的末尾是以'/'结尾并且该路径去掉末尾的'/'以后并没有被注册.那么将会去掉'/'并且为其绑定一个Redirect到现在的路径.
  
我自己写起来都觉得绕,举个例子就清楚了.
  
我注册了一个路径"/home/",但是没有注册"/home",那么如果用户访问了"/home"会发生什么呢?是的,会被Redirect到"/home/".
  
需要注意的是,这里的muxEntry中的explicit没有填,也就是说是false,那么即是可以覆盖的.

* ServeMux.ServeHTTP()
  ServeHTTP会检测非法的URI(* )
  
如果通过检测就会调用自身的Handler()来返回注册的Handler,随后调用Handler的ServeHTTP方法



运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-597113-1-1.html 上篇帖子: slice小结 下篇帖子: golang中sort包用法
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表