http_路由选择器

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.Handlehttp.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.Handlehttp.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包所提供的路由选择器功能太过于简单。无法实现生产过程中的一些复杂的路由功能。第三方包的功能也大致相同, 只不过在路由注册,选择中加入了其他的功能。

你可能感兴趣的:(http_路由选择器)