http包是Go语言编写Web应用的基石, 它提供了高性能的http支持, Go语言甚至可以不使用任何第三方框架就可以完成Web应用的开发, 同时http包也是Go中其他第三方框架的基础。
Handler接口
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
Handler接口是http路由的基础, 它要求我们为路由选择器实现ServeHttp方法,这个方法接收ResponseWriter
对象和Request
对象指针两个参数。
当我们创建一个Server的时候, 会让我们指定路由选择器, 这个路由选择器必须实现Handler接口。
func main() {
router := http.NewServeMux()
server := &http.Server{
Handler: router,
}
}
当然我们也可以不指定或指定为nil,那么http包就会使用默认的路由选择器。 我们接下来看下默认路由选择器的实现方法。
var DefaultServeMux = &defaultServeMux
var defaultServeMux ServeMux
type ServeMux struct {
mu sync.RWMutex
m map[string]muxEntry
hosts bool // whether any patterns contain hostnames
}
type muxEntry struct {
h Handler
pattern string
}
这个默认的路由选择器就是一个ServeMux对象, 其中m map[string]muxEntry
中存储这我们注册到路由选择器中的路由。
当我们使用http.Handle
和http.HandleFunc
的时候,都是将路由和对应的处理逻辑注册到这个默认的路由选择器上。上面曾提到过路由选择器必须实现Handler接口,接下来我们看下默认的路由选择器如何实现这个接口
func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) {
h, _ := mux.Handler(r)
h.ServeHTTP(w, r)
}
上面的代码删除了特殊情况处理的部分,有兴趣的可以查看源码。
http包默认的路由选择器的ServeHttp方法主要的功能就是这两行代码。h, _ := mux.Handler(r)
依据给定的Request查找到对应的处理对象。这里我们可以看到查找出来的处理对象,也实现了Handler
接口。这就需要去查看下路由选择器的路由注册功能。
func (mux *ServeMux) Handle(pattern string, handler Handler) {
mux.mu.Lock()
defer mux.mu.Unlock()
if pattern == "" {
panic("http: invalid pattern")
}
if handler == nil {
panic("http: nil handler")
}
if _, exist := mux.m[pattern]; exist {
panic("http: multiple registrations for " + pattern)
}
if mux.m == nil {
mux.m = make(map[string]muxEntry)
}
mux.m[pattern] = muxEntry{h: handler, pattern: pattern}
if pattern[0] != '/' {
mux.hosts = true
}
}
上面的代码就是http包提供的路由选择器的路由注册功能实现,他要求我们提供对应的路由pattern和相应的处理方法(一个实现了Handler接口的对象)。
也就是说这个路由选择器是一个Handler接口, 而且向其中注册的路由也要是一个Handler接口。当Server
调用路由选择器的ServeHttp方法的时候, 路由选择器将会根据请求路径查找到相应的处理对象,调用它的ServeHttp方法。这就是http包提供的路由选择器的功能。
因为一般我们的处理逻辑都是一个函数, 所以http包也提供了函数路由注册的功能:
func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
if handler == nil {
panic("http: nil handler")
}
mux.Handle(pattern, HandlerFunc(handler))
}
type HandlerFunc func(ResponseWriter, *Request)
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
f(w, r)
}
它提供的功能很简单, 就是将我们所提供的函数转化为一个实现了Handler接口的对象,然后调用之前的Handle方法。
当我们使用http.Handle
和http.HandleFunc
的时候底层也是调用的上面的两个方法, 只不过他们是在默认路由上完成注册:
func Handle(pattern string, handler Handler) {
DefaultServeMux.Handle(pattern, handler)
}
func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
DefaultServeMux.HandleFunc(pattern, handler)
}
到此http包提供的路由选择器主要的功能已经表完了。可以看到我们很容易就可以替换http包所提供的路由选择器。只需要指定路由选择器为一个实现了Handler
接口的对象。
Go中有很多第三方的包提供路由的功能, 因为http包所提供的路由选择器功能太过于简单。无法实现生产过程中的一些复杂的路由功能。第三方包的功能也大致相同, 只不过在路由注册,选择中加入了其他的功能。