启动web服务非常简单,只需要使用http.HandleFunc(),http.ListenAndFunc()这两个函数就可以启动一个web服务了。
HandleFunc()
http.HandleFunc()底层会调用ServeMux.HandleFunc(),
我们传进来的handler是一个函数,但是如果直接把handler传给mux.Handle()则会报错,因为handler没有实现Handler这个接口。实现Handler接口需要实现ServeHTTP(),所以对handler进行强制类型转换,转换成HandlerFunc类型,HandlerFunc实现了ServeHTTP()。
现在看ServeMux.Handle(),从注释中可以看出Handle主要是给指定的pattern注册handler的,
看看ServeMux,这个结构体中有m和es这两个存储handler的字段,当注册handler的时候,首先把handler注册进m这个map中,用来进行精确查找,之后判断pattern的最后一个字符是不是 '/' ,如果是 '/',加入es中。
ListenAndServe()
当调用ListenAndServe()时,传入的handler是nil,然后会调用net.Listen()监听端口;在Server.Serve()的for循环中对于每一个请求都会起一个协程进行处理。
在conn.serve()中调用conn.readRequest()从连接中读取请求,然后调用serverHandler.ServeHTTP(),
在serverHandler.ServeHTTP()中,首先判断handler是否为nil,因为我们在调用ListenAndServe()时,传入的handler是nil,所以这里handler为DefaultServeMux。DefaultServeMux的类型为 *ServeMux ,
当执行handler.ServeHTTP()时,真正调用的是ServeMux.ServeHTTP();
ServeMux.ServeHTTP()中mux.Handler()会返回一个handler来处理该请求,会根据传入的路径进行不同的操作。如果我们注册了/tree/的handler,没有注册/tree的handler,那么会redirect到/tree/。
ServeMux.handler()中调用match()返回最匹配的handler,首先会从ServeMux.m中寻找,如果找到直接返回,否则在循环遍历es的过程中看path的前缀是否是pattern(es中的handler按照pattern的长度从长到短排序的)。
找到了handler之后返回ServeMux.ServeHTTP()中调用h.ServeHTTP(w, r),这里的h其实是http.HandlerFunc,调用ServeHTTP()也就是调用我们自己注册的handler函数。