开启一个HTTP服务,有以下两种方式:
// 方式一:http.HandleFuncfunc main() {http.HandleFunc("/", test)http.ListenAndServe(":8090", nil)}func test(w http.ResponseWriter, r *http.Request) {}// 方式二:http.Handletype indexHandler struct {}func (ih *indexHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {// dosomething}func main() {http.Handle("/", &indexHandler{})http.ListenAndServe(":8001", nil)}
路由注册
HandleFunc
注意:
http.HandleFunc是一个函数, http.HanderFunc是一个类型声明。(名称相差一个字母r)。
http.Handle是一个函数,Hander是一个接口。(名称相差一个字母r)
HeadleFunc函数源码如下。

由上图可见,HandleFunc会使用HeadlerFunc类型转化的方式,使得传入的参数handler实现了ServeHTTP的方法。
Handle

func (mux *ServeMux) Handle(pattern string, handler Handler) {mux.mu.Lock()defer mux.mu.Unlock()// 隐藏了一些参数验证的代码e := muxEntry{h: handler, pattern: pattern}mux.m[pattern] = eif pattern[len(pattern)-1] == '/' {// 根据url的长度,查找新的路由方法应该插入到那里mux.es = appendSorted(mux.es, e)}if pattern[0] != '/' {mux.hosts = true}}

服务监听
源码速览

func (srv *Server) Serve(l net.Listener) error {for {rw, err := l.Accept()if err != nil {...}c := srv.newConn(rw)c.setState(c.rwc, StateNew) // before Serve can returngo c.serve(connCtx) // 开启一个线程处理请求,但是一个tcp连接只能同一时间只能处理一个请求}}func (c *conn) serve(ctx context.Context) {// HTTP/1.x from here on.for {w, err := c.readRequest(ctx)if err != nil {...}serverHandler{c.server}.ServeHTTP(w, w.req)...}}func (sh serverHandler) ServeHTTP(rw ResponseWriter, req *Request) {// http.ListenAndServe(":8001", nil),所有handle为空if handler == nil {handler = DefaultServeMux // 使用默认路由,也就是http.HandleFunc注册的路由}handler.ServeHTTP(rw, req)}
流程分析

1 实例化Server
2 调用Server的ListenAndServe()
3 调用net.Listen(“tcp”, addr)监听端口
4 启动一个for循环,在循环体中Accept请求
5 对每个请求实例化一个Conn,并且开启一个goroutine为这个请求进行服务go c.serve()
6 读取每个请求的内容w, err := c.readRequest()
7 判断handler是否为空,如果没有设置handler(这个例子就没有设置handler),handler就设置为DefaultServeMux
8 调用handler的ServeHttp
9 在这个例子中,下面就进入到DefaultServeMux.ServeHttp
10 根据request选择handler,并且进入到这个handler的ServeHTTP
mux.handler(r).ServeHTTP(w, r)
11 选择handler:
A 判断是否有路由能满足这个request(循环遍历ServeMux的muxEntry)
B 如果有路由满足,调用这个路由handler的ServeHTTP
C 如果没有路由满足,调用NotFoundHandler的ServeHTTP
路由匹配

当注册路由 /abc/时,会默认注册/abc,若/abc已经存在则会被覆盖。此外/abc/可以匹配到/adc/1。
但/abc不能匹配/abc/。
前文有说,路由注册的时候,mux.es中会根据url长度进行存储,所以,此处匹配时,会优先匹配到最长的字符串。
例如: /abc/1/2 会匹配到 /abc/1/ 而不是 /abc/
http问题
1、不能匹配路径参数
2、 不支持正则路由
