先贴一段代码
package main
import (
"net/http"
"fmt"
"log"
)
func hello(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
fmt.Printf("%+v\n", *r.URL)
fmt.Fprintln(w, "Hello world")
}
func main() {
http.HandleFunc("/", hello)
err := http.ListenAndServe(":9090", nil)
if err != nil {
log.Fatal(err)
}
}
这里监听本地的9090端口,使用 http.HandleFunc 将URL为“/”的请求将其转向名为hello的方法。这是比较常见的Golang的简单Web的实现,但是看着会觉得很奇怪,建议先把代码跑起来,然后我们再来看看源码中Handler的定义先。
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
如代码中所示,Handler实际上一个接口,实现了 ServeHTTP(ResponseWriter, *Request) 这个函数,就相当于实现了一个Handler。通俗讲Handler就是处理输入输出流的函数,将Handler注册到路由器,等同于将特定的URL跟这个函数绑定起来,当客户端请求访问这个URL,路由器就会使用这个函数进行操作。
可能会有童鞋会疑问,hello这个函数并不是一个Handler,为什么可以作为Handler注册一个URL。这是因为这里有一个函数叫做HandleFunc,这里就讲讲HandleFunc的原理吧。先把源码列出来:
func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
DefaultServeMux.HandleFunc(pattern, handler)
}
HandleFunc传入一个字符串(URL)和一个func(ResponseWriter, Request),hello这个函数是符合func(ResponseWriter, Request)的要求的,然后使用DefaultServeMux进行处理,DefaultServeMux又是什么?在server.go的源码中可以轻松找到DefaultServeMux的定义
type ServeMux struct {
mu sync.RWMutex
m map[string]muxEntry
hosts bool // whether any patterns contain hostnames
}
....
// DefaultServeMux is the default ServeMux used by Serve.
var DefaultServeMux = &defaultServeMux
var defaultServeMux ServeMux
由源码可以知道DefaultServeMux相当于一个公共的路由,一个公有变量,URL和Handle就是注册到这个路由上的。需要注意的是ServeMux的成员变量,有一个sync.RWMutex,了解过Golang并发的应该知道,这是一个读写锁(Mutiple read,single write lock, 多读单写锁,允许多个读操作并行执行,但写操作会完全互斥,在读取操作比较频繁时比sync.Mutex有着更好的性能表现),这应该也是考虑到作为Web服务器,读取操作会比较频繁。接下来看mux.Handle(pattern, HandlerFunc(handler))去到哪一步,应该看到这里有一个函数HandlerFunc(handler):
type HandlerFunc func(ResponseWriter, *Request)
// ServeHTTP calls f(w, r).
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
f(w, r)
}
看到这里你就应该明白,为什么hello这个函数没有实现Handler方法也是一个Handler,因为HandlerFunc把hello强制实现ServeHTTP(w ResponseWriter, r *Request),所以hello这个函数也就是一个Handler。
这里是路由的最后一步了
type muxEntry struct {
h Handler
pattern string
}
// Handle registers the handler for the given pattern.
// If a handler already exists for pattern, Handle panics.
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
}
}
公有变量DefaultServeMux将Handler注册,这里就用到了读写锁以及一个私有结构muxEntry,到这里,路由注册就结束了。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。