Go语言是一个神奇的语言,尤其是函数式编程,
func HandleFunc(pattern string, handler func(ResponseWriter, *Request))
就是一个典型。这个函数就是注册默认路由。
HandleFunc 的第一个参数指的是请求路径,第二个参数是一个函数类型,表示这个请求需要处理的事情。没有处理复杂的逻辑,而是直接给DefaultServeMux处理,如源码:
func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
DefaultServeMux.HandleFunc(pattern, handler)
}
DefaultServeMux 是ServeMux一个全局实例,
// DefaultServeMux is the default ServeMux used by Serve.
var DefaultServeMux = &defaultServeMux
var defaultServeMux ServeMux
这个实例在被申明的时候初始化了,只要使用了DefaultServeMux这个变量,其实就是同一个指针而已,也就是独一份。
DefaultServeMux.HandleFunc(pattern, handler) 函数其实也没有做什么,直接调用路由注册:
// HandleFunc registers the handler function for the given pattern.
func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
mux.Handle(pattern, HandlerFunc(handler))
}
把自定义处理业务的函数进行路由注册,HandlerFunc(handler) 这个处理其实是类型转化,把函数handler func 类型转化成HandlerFunc类型,是一个强制转化,只要函数的参数类型一致,即可转化。我们来看一个HandlerFunc是如何定义的:
type HandlerFunc func(ResponseWriter, *Request)
// ServeHTTP calls f(w, r).
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
f(w, r)
}
从type可以看出 HandlerFunc 就是一个自定义类型,被定义成
func(ResponseWriter, *Request)
函数。所以只要符合此标准的函数,都可以转化成HandlerFunc,而这个函数实现了接口:
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
这个接口就是路由中,匹配的处理方法。
根据go对接口的定义,只有实现了接口的所有方法,就实现了这个接口。
我们来看是如何注册路由的,需要理解如下两个结构
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//请求路径
}
处逻辑源码如下:
// Handle 根据给定的请求路劲进行注册路由
// 如果Handle已经存在,就直接报错
func (mux *ServeMux) Handle(pattern string, handler Handler) {
//进行加锁,高并发处理
mux.mu.Lock()
//释放锁
defer mux.mu.Unlock()
//请求路径为空,直接报错
if pattern == "" {
panic("http: invalid pattern " + pattern)
}
//Handle不存在,直接报错
if handler == nil {
panic("http: nil handler")
}
//如果Handle已经存在,就直接报错
if mux.m[pattern].explicit {
panic("http: multiple registrations for " + pattern)
}
//路由表不存在,创建一个,这个路由表是一个映射MAP
//key 就是请求路径 value是muxEntry 包含具体路由信息
if mux.m == nil {
mux.m = make(map[string]muxEntry)
}
mux.m[pattern] = muxEntry{explicit: true, h: handler, pattern: pattern}
//如果首字母不是‘/’ 包含hostName
if pattern[0] != '/' {
mux.hosts = true
}
// Helpful behavior:
// If pattern is /tree/, insert an implicit permanent redirect for /tree.
// It can be overridden by an explicit registration.
n := len(pattern)
//如何是像/tree/ 请求注册路由,而且/tree 还没有注册过
if n > 0 && pattern[n-1] == '/' && !mux.m[pattern[0:n-1]].explicit {
// If pattern contains a host name, strip it and use remaining
// path for redirect.
path := pattern //保存原始路径
if pattern[0] != '/' { //如果首字母不是 ‘/’
// In pattern, at least the last character is a '/', so
// strings.Index can't be -1.
path = pattern[strings.Index(pattern, "/"):] //返回最近的/之后的串作为请求路径
}
//构建请求URL 直接重定向 而且注册的注册路径有/tree/ /tree
url := &url.URL{Path: path}
mux.m[pattern[0:n-1]] = muxEntry{h: RedirectHandler(url.String(), StatusMovedPermanently), pattern: pattern}
}
}
以上是对函数
func HandleFunc(pattern string, handler func(ResponseWriter, *Request))
调用过程分析
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。