初识HTTP服务
func indexHandler(w http.ResponseWriter, req *http.Request) {
fmt.Fprintf(w, "URL.Path = %q\n", req.URL.Path)
}
func main() {
http.HandleFunc("/", indexHandler)
err := http.ListenAndServe("9999", nil)
log.Fatal(err)
}
http.HandleFunc()
保存路由(pattern)与处理函数(handler)之间的映射关系到ServeMux中
// 注册pattern与handler之间的映射关系
func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
DefaultServeMux.HandleFunc(pattern, handler)
}
DefaultServeMux本质是ServeMux,故DefaultServeMux.HandleFunc()实质是ServeMux.HandleFunc()
var DefaultServeMux = &defaultServeMux
var defaultServeMux ServeMux
type muxEntry struct {
h Handler
pattern string
}
type ServeMux struct {
mu sync.RWMutex // 读写锁
m map[string]muxEntry // map,存储handler与pattern之间的映射关系
es []muxEntry
hosts bool
}
func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
// 如果handler为空,直接退出程序。因为每一个pattern都应该对应一个handler
if handler == nil {
panic("http: nil handler")
}
// 调用ServeMux.Handle, 并将handler类型转换为HandlerFunc。
mux.Handle(pattern, HandlerFunc(handler))
}
func (mux *ServeMux) Handle(pattern string, handler Handler) {
// 使用了ServeMux结构体中的写锁
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)
}
// 初始化一个muxEntry,并添加到map中
e := muxEntry{h: handler, pattern: pattern}
mux.m[pattern] = e
if pattern[len(pattern)-1] == '/' {
mux.es = appendSorted(mux.es, e)
}
if pattern[0] != '/' {
mux.hosts = true
}
}
http.ListenAndServe()
1、建立tcp连接监听端口 2、可以自定义服务分发器(将请求的url转发到对应的handler进行处理),如果不自定义则会有默认的服务分发器(DefaultServeMux)
// 监听TCP网络地址addr,然后调用Serve来处理传入连接的请求
func ListenAndServe(addr string, handler Handler) error {
server := &Server{Addr: addr, Handler: handler}
return server.ListenAndServe()
}
// Server定义了运行一个HTTP服务器的参数
type Server struct {
Addr string // tcp连接的端口号
Handler Handler // 分发路由的Handler
......
}
func (srv *Server) ListenAndServe() error {
......
// tcp的端口号
addr := srv.Addr
if addr == "" {
addr = ":http"
}
// 监听addr端口
ln, err := net.Listen("tcp", addr)
if err != nil {
return err
}
return srv.Serve(ln)
}
func (srv *Server) Serve(l net.Listener) error {
......
ctx := context.WithValue(baseCtx, ServerContextKey, srv)
// 无限循环接受连接,并为每一个连接开启一个goroutine进行处理
for {
// 出现新的连接
rw, err := l.Accept()
if err != nil {
select {
case <-srv.getDoneChan():
return ErrServerClosed
default:
}
if ne, ok := err.(net.Error); ok && ne.Temporary() {
if tempDelay == 0 {
tempDelay = 5 * time.Millisecond
} else {
tempDelay *= 2
}
if max := 1 * time.Second; tempDelay > max {
tempDelay = max
}
srv.logf("http: Accept error: %v; retrying in %v", err, tempDelay)
time.Sleep(tempDelay)
continue
}
return err
}
connCtx := ctx
if cc := srv.ConnContext; cc != nil {
connCtx = cc(connCtx, rw)
if connCtx == nil {
panic("ConnContext returned nil")
}
}
tempDelay = 0
// 创建新的连接
c := srv.newConn(rw)
c.setState(c.rwc, StateNew, runHooks) // before Serve can return
// 开启一个goroutine处理
go c.serve(connCtx)
}
}
func (c *conn) serve(ctx context.Context) {
......
inFlightResponse = w
// 调用handler函数,将pattern分发到对应的处理函数(handleFunc)。
//初始化serverHandler,serverHandler实现了ServeHTTP接口
serverHandler{c.server}.ServeHTTP(w, w.req)
inFlightResponse = nil
......
}
type serverHandler struct {
srv *Server
}
func (sh serverHandler) ServeHTTP(rw ResponseWriter, req *Request) {
// 取出Server的handler
handler := sh.srv.Handler
// 如果没有自定义的handler(http.ListenAndServe中的第二个参数,这个参数的作用是处理路由分发),
//就使用DefaultServeMux作为默认的服务分发器,即将pattern与handler匹配起来
if handler == nil {
handler = DefaultServeMux
}
......
// 调用handler的ServeHTTP
handler.ServeHTTP(rw, req)
}
// 由于使用了DefaultServeMux,所以handler.ServeHTTP()就是DefaultServeMux.ServeHTTP()
// 又因为DefaultServeMux==ServeMux,所以最终调用的是ServeMux.ServeHTTP()
func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) {
if r.RequestURI == "*" {
if r.ProtoAtLeast(1, 1) {
w.Header().Set("Connection", "close")
}
w.WriteHeader(StatusBadRequest)
return
}
// 根据r中的url,在map中找到handler
h, _ := mux.Handler(r)
// 调用handler.ServeHTTP()
h.ServeHTTP(w, r)
}
代码一直到最后,h指的是ServeMux中m的muxEntry的handler,此处的handler是http.HandleFunc()第二个参数,也就是最开始代码中的indexHandler,此处存在一个疑问,indexHandler为什么能调用ServeHTTP这个接口?此处并没有真正调用muxEntry中的handler,也就是路由过来的请求并没有被处理。
// Handler接口中只有一个ServeHTTP方法,上述代码中调用的ServeHTTP都是实现的Handler接口
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
// 定义func(ResponseWriter, *Request)这一函数类型为HandlerFunc,也就是说只要是
// 函数的参数是func(ResponseWriter, *Request)这种类型的都是HandlerFunc
type HandlerFunc func(ResponseWriter, *Request)
// HandlerFunc实现了ServeHTTP方法,也就是只要函数为func(ResponseWriter, *Request)
// 此种类型的都默认实现了Handler接口,也就可以使用ServeHTTP方法。
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
// HandlerFunc此种类型的函数在调用ServeHTTP时,都会调用f(w, r)
// 在本文表现为,indexHandler为HandlerFunc类型的函数,调用了f(w, r),也就是调用了
//indexHandler(w ResponseWriter, r *Request),即将路由过来的请求按照indexHandler()进行处理
f(w, r)
}
总结
设计方法
定义函数为一种类型,函数实现接口的方法,可以回调函数。
流程总结
- 调用http.HandleFunc()
- 调用DefaultServeMux 的 HandleFunc,
- 调用了 DefaultServeMux 的 Handle
- 向DefaultServeMux的map中增加对应的handler和pattern的映射关系
- 调用http.ListenAndServe()
- 初始化Server,存储监听的端口号以及设置路由规则
- 调用Server.ListenAndServe()
- 调用net.Listen()监听端口
- 开启无限循环,从队列种拿Accpet
- 对每一个Accept初始化一个连接,并开启一个goroutine
- 读取请求内容
- 判断handler是否为空,如果为空就设置handler为DefaultServeMux
- 调用handler.ServeHttp(),即根据路由规则调用处理函数