默认路由注册器分析
使用http.handlerFunc
http.HandleFunc("/handleFunc", func(writer http.ResponseWriter, request *http.Request) {
writer.Write([]byte("我是HandleFun函数类型"))
})
http.ListenAndServe(":8080", nil)
- 注册了一个
/handlerFun
接口 - 启动服务
路由注册源码分析
既然能直接将一个接口对应一个方法,底部实现应该是有一个变量进行存储,如map[string]muxEntry。最后在http协议分析的时候,匹配请求地址,找到了就执行对应的handler方法。
疑问1?http.HandleFunc()仅仅是一个函数,里面注册的路由如何能与http.ListenAndServe()这个独立方法关联在一起呢?
答:既然是两个独立的函数,他们内部的变量肯定不能共享,所以要想注册的路由在启动分析中使用,则一定是设置了一个全局变量。所以追踪代码找到了DefaultServeMux
默认的路由服务
源码http.server.go line:2451
func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
// 调用ServerMux中的HandleFunc来注册回调方法,这里仅仅是对匿名函数的一层封装,后面我们可以试着来手动封住,实现一样的功能
DefaultServeMux.HandleFunc(pattern, handler)
}
// line:2436
func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
if handler == nil {
panic("http: nil handler")
}
// 这里调用了ServeMux中的handle方法,路由=>处理Handler接口变量!因为匹配到了路由,那么我们要执行什么代码呢?肯定是要定义一个接口,然后外部统一实现这个接口,在框架底层就直接调用这个接口中的方法就行。这个就是接口的好处了。
mux.Handle(pattern, HandlerFunc(handler))
}
使用http.handle
func Handle(pattern string, handler Handler) { DefaultServeMux.Handle(pattern, handler) }
上面这里还是使用的DefaultServeMux,这里是直接传的参数是实现了handler的接口,相比于http.handleFunc这个更加是底层一步的方法。这里需要手动实现handler接口,而http.handleFunc是只要传入一个匿名函数,它会帮实现handler接口。区别仅此而已
自己实现handleFunc
因为想传入匿名函数,所以定义一个函数类型就行了,然后这个函数类型实现handler接口就ok了嘛。其实实现完成之后发现这个在go 中已经封装了。就是http.HandlerFunc这个类型
package main
import (
"fmt"
"net/http"
)
// 定义一个类型是函数类型,因为我也像http.handleFunc一样传入匿名函数
type HandleMyFunc func(writer http.ResponseWriter, request *http.Request)
// 这里是实现了handler接口
func (f HandleMyFunc) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
fmt.Println("ServeHttp")
f(writer, request)
}
func main() {
var hh HandleMyFunc
hh = func(writer http.ResponseWriter, request *http.Request) {
writer.Write([]byte("模拟handFunc1"))
}
http.Handle("/handleMyFunc1", hh)
http.Handle("/handleMyFunc2", HandleMyFunc(func(writer http.ResponseWriter, request *http.Request) {
writer.Write([]byte("模拟handFunc2"))
}))
http.ListenAndServe(":8080", nil)
}
路由匹配规则
type ServeMux struct {
mu sync.RWMutex
m map[string]muxEntry
es []muxEntry // slice of entries sorted from longest to shortest.
hosts bool // whether any patterns contain hostnames
}
- m 是一个map,会在匹配的时候优先精确匹配
- es 是路由注册的时候以/为结尾,会保存在这个切片中(长度从大到小),后面匹配的时候,如果精确匹配没有结果,则会以这个里面的路由进行就近匹配