Loading... > 本文由 [简悦 SimpRead](http://ksria.com/simpread/) 转码, 原文地址 [studygolang.com](https://studygolang.com/articles/8395) 在 golang 当中启动一个 http 服务非常简单,比如: ```go http.HandFunc("/",func(w http.RequestWriter,r *http.Request){ io.WriteString(w,"hello world!") }) http.ListenAndServer(":9090") //outprint hello world! ``` 为什么 访问 `localhost:9090` 就能打印出 Hello world 呢?这背后究竟发生了呢?下面我们就一层一层揭开这个面纱!追踪 `http.HandFunc `函数,发现它调用了 : ```go DefaultServeMux.HandleFunc(pattern, handler) ``` DefaultServeMux 实际是 ServerMux(路由)的一个默认被初始化的一个结构,所以这个 http.handfunc 最底层调用的是 ServeMux.HandleFunc。在看这个函数之前,我们先看看,我们的第一个重要的结构体:ServerMux(路由) ```go type ServeMux struct { mu sync.RWMutex //并发锁 m map[string]muxEntry //路由map hosts bool // whether any patterns contain hostnames } type muxEntry struct { explicit bool h Handler //当前路由的处理器 pattern string //路由字符串 eq:/hello } ``` 分析:一个 ServeMux 通过一个私有的 muxEntry map 保存了所有的路由。每个 muxEntry 里面都包含有一个 h(handler)处理器,用来出来这个路由的逻辑。 回到上面的 ServerMux.HandleFunc。我们继续追踪这个函数,发现它调用了 ServeMux.Handle() 这个方法: ```go ServeMux.Handle(pattern string, handler Handler) //mux.Handle(pattern, HandlerFunc(handler)) 调用 ``` ServeMux.Handle 这个函数 需要两个参数,一个参数 路由的 path 路径,另一个是一个 handler(拥有这个路径具体处理逻辑的函数),这个 handler 是什么东西呢? ```go type Handler interface { ServeHTTP(ResponseWriter, *Request) } ``` Hander 就是一个拥有 ServerHTTP 函数的类型。回到上面的 ServeMux.Handle(path,HandleFunc(handle)), 我们发现,从一开始,我们传进去的只是一个具体的函数,就是: ```go func(w http.RequestWriter,r *http.Request){ io.WriteString(w,"hello world!") } ``` 这个函数,但是它怎么就是变成 Handler 了呢?我们看看 HandlerFunc 这个东西?这个东西比较有意思。 ```go type HandlerFunc func(ResponseWriter, *Request) // ServeHTTP calls f(w, r). func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) { f(w, r) } ``` HandlerFunc 是一个函数 类型,同时它有一个 ServeHTTP 这个方法,也就是它已经实现了 Handler 这个接口,所以 可以用在所有以 Handler 为参数的地方,也就是可以用在 ServeMux.Handle() 的第 2 个参数位置上。同时在 HandFunc.ServeHTTP 内部它调用的 是 HandFunc 这个函数 (调用它自己),换句话说,就是一个具体的函数,通过 HandleFunc 这个类型转换以后就变成了 Handle 类型。这个技巧我们可以学习一下。 下面,我们看看,ServeMux.Handle 内部的具体实现: ```go func (mux *ServeMux) Handle(pattern string, handler Handler) { mux.mu.Lock() defer mux.mu.Unlock() if pattern == "" { panic("http: invalid pattern " + pattern) } if handler == nil { panic("http: nil handler") } if mux.m[pattern].explicit { panic("http: multiple registrations for " + pattern) } mux.m[pattern] = muxEntry{explicit: true, h: handler, pattern: pattern} // if pattern[0] != '/' { mux.hosts = true } n := len(pattern) if n > 0 && pattern[n-1] == '/' && !mux.m[pattern[0:n-1]].explicit { path := pattern if pattern[0] != '/' { path = pattern[strings.Index(pattern, "/"):] } url := &url.URL{Path: path} mux.m[pattern[0:n-1]] = muxEntry{h: RedirectHandler(url.String(), StatusMovedPermanently), pattern: pattern} } } ``` 这里简单说 就是 把 path,和对应的 handle 添加到 ServerMux.muxEntry 里面。到这里,我们对路由的分析就完成了。现在我们在回顾一下: 最后修改:2024 年 01 月 16 日 © 允许规范转载 打赏 赞赏作者 支付宝微信 赞 如果觉得我的文章对你有用,请随意赞赏