func main() { http.HandleFunc("/say",say) err := http.ListenAndServe(":8080", nil) if err != nil { log.Fatal(err.Error()) } } func say(w http.ResponseWriter, r *http.Request) { // }上面是一段启动web服务的代码通过监听8080端口 并且在启动钱注册了say()函数
如在浏览器输入 localhost:8080/say就会默认回调say函数 今天就来分析一下这其中的大致过程
首先在go当中做请求转发可以使用系统默认的路由器也可以使用自己定制的路由器但是都必须要去实现Handler接口
type Handler interface { ServeHTTP(ResponseWriter, *Request) }在路由这一个大量涉及到Handler这个接口不仅仅是自定义路由和默认路由要实现这个接口 甚至文章开头的例子中say函数在注册之后都是先强制类型转换为server.go中的HandleFunc类型 而又由于HandleFunc可以实现了ServeHttp方法 所以就实现了Handler接口 所以每一个注册的函数其实最后都被当做Handler类型来做处理
下面介绍路由请求分发的大致过程
http.ListenerAndServer(addr,nil) 监听端口 addr 地址 第二个参数设置你自己实现的路由 如果为nil则使用默认的
通过返回的端口监听器监听addr端口 通过l.Aceept 接受连接 go c.serve()为该连接创建一个新的协程去专门处理 因为有for循环所以继续等待接受
func (srv *Server) Serve(l net.Listener) error { defer l.Close() var tempDelay time.Duration // how long to sleep on accept failure for { rw, e := l.Accept() if e != nil { if ne, ok := e.(net.Error); ok && ne.Temporary() { if tempDelay == 0 { tempDelay = 5 * time.Millisecond } else { tempDelay *= 2 } if max := 1 * time.Second; tempDelay > max { tempDelay = max } log.Printf("http: Accept error: %v; retrying in %v", e, tempDelay) time.Sleep(tempDelay) continue } return e } tempDelay = 0 c, err := srv.newConn(rw) if err != nil { continue } go c.serve() } }
下图是个我自己总结的比较关键的几步 先看图 再解释
客户端来请求 然后接收 启动协程处理 其中serverHandler这一步是server.go内部私有的结构体用来判断是选择开发者自己实现的路由还是默认的路由
无论是哪个路由 都是会调用该路由的ServeHTTP 然后路由在ServeHTTP内部自己处理具体的分发请求
如果是默认的路由则最终会根据路径 去匹配对应的Handler然后返回 注意这里的路径就是一开始注册的路径一个路径对应一个函数也就是一个Handler
将该Handler返回之后则调用该Handler的ServeHTTP 在这个方法内部则是直接调用自己(因为本身就是个函数)然后就是具体外部的方法实现了
有疑问加站长微信联系(非本文作者)