golang Http服务浅析
golang的HTTP包提供了了很强大的功能,开发人员即使不使用框架也可以很方便的进行开发。下面就简单说一下开发web应用时HTTP包都做了哪些工作。 我们在建立一个WEB应用的时候经常会这样使用: http.HandleFunc("/hello",func(writer http.ResponseWriter,request *http.Request) { writer.Write([]byte("hello")) }) http.ListenAndServe(":8080",nil) 这样我们访问 下面从两个介绍HTTP的工作流程: 一 注册过程注册的代码是: http.HandleFunc("/hello",request *http.Request) { writer.Write([]byte("hello")) }) 看一下 var DefaultServeMux = &defaultServeMux var defaultServeMux ServeMux func HandleFunc(pattern string,handler func(ResponseWriter,*Request)) { DefaultServeMux.HandleFunc(pattern,handler) //调用ServeMux的HandleFunc函数 } 这里发现http.HandleFunc调用的是DefaultServeMux的HandleFunc函数,DefaultServeMux是ServeMux类型的变量。下面看看ServeMux。 type ServeMux struct { mu sync.RWMutex m map[string]muxEntry //key是路径 hosts bool } type muxEntry struct { h Handler //通过HandleFunc函数传过来的handler pattern string //路径 } func (mux *ServeMux) HandleFunc(pattern string,*Request)) { mux.Handle(pattern,HandlerFunc(handler)) //调用Handle } func (mux *ServeMux) Handle(pattern string,handler Handler) { mux.mu.Lock() defer mux.mu.Unlock() //.... mux.m[pattern] = muxEntry{h: handler,pattern: pattern} //.... } 这里HandleFunc函数调用Handle函数,然后通过mux.m[pattern] = muxEntry{h: handler,pattern: pattern}把handler存储到muxEntry然后放到ServeMux的map中。 type HandlerFunc func(ResponseWriter,*Request) func (f HandlerFunc) ServeHTTP(w ResponseWriter,r *Request) { f(w,r) } HandlerFunc和我们传入的Handler的函数签名是一样的,只是它还有一个ServeHTTP函数,这个函数会调用我们传入的handler。可以看出HandlerFunc只是对我们传入的handler进行了包装并提供ServeHTTP来调用 这里总结一下注册handler的流程: 二.监听过程调用http.ListenAndServe函数,看看它的代码 func ListenAndServe(addr string,handler Handler) error { server := &Server{Addr: addr,Handler: handler} return server.ListenAndServe() //调用Server类型的同名方法 } func (srv *Server) ListenAndServe() error { addr := srv.Addr if addr == "" { addr = ":http" } ln,err := net.Listen("tcp",addr) //监听端口 if err != nil { return err } return srv.Serve(tcpKeepAliveListener{ln.(*net.TCPListener)}) } func (srv *Server) Serve(l net.Listener) error { //.... for { rw,e := l.Accept() //等待请求 //... } } http.ListenAndServe调用Server.ListenAndServe方法,该方法首先监听端口net.Listen("tcp",addr) ,然后调用了Server.Serve方法来等待请求的到来。 总结一下: 三.处理请求处理请求的逻辑也是在Server.Serve方法中。 func (srv *Server) Serve(l net.Listener) error { //.... for { rw,e := l.Accept() //等待请求 //... c := srv.newConn(rw) //这里创建了一个conn结构体,它代表一个连接 c.setState(c.rwc,StateNew) // before Serve can return go c.serve(ctx) } } 调用conn.serve方法: func (c *conn) serve(ctx context.Context) { //... serverHandler{c.server}.ServeHTTP(w,w.req) //... } func (sh serverHandler) ServeHTTP(rw ResponseWriter,req *Request) { handler := sh.srv.Handler if handler == nil { handler = DefaultServeMux } handler.ServeHTTP(rw,req) } conn.serve调用serverHandler的ServeHTTP方法,这个方法会调用DefaultServeMux(如果我们没有手动设置新的ServerMux的话)的ServeHTTP方法。 到目前为止,我们已经知道实现ServeHTTP的类型有两个:ServerMux和HandlerFunc,也就是他们都实现了下面的Handler接口。 type Handler interface { ServeHTTP(ResponseWriter,*Request) } 这样说来ServeMux和HandlerFunc本质上都是用来相应请求的handler。ServerMux的m字段保存了我们注册的多个HandlerFunc。HandlerFunc作为一个Handler接口的实现是我们自己编写的用来处理请求的,那么ServerMux做为Handler接口的实现的实现是用来干什么的呢?这里可以直接给出答案:是用来做路由的。 func (mux *ServeMux) ServeHTTP(w ResponseWriter,r *Request) { //... h,_ := mux.Handler(r) //获取对应的handler h.ServeHTTP(w,r) //执行handler } func (mux *ServeMux) Handler(r *Request) (h Handler,pattern string) { //... return mux.handler(host,r.URL.Path) //不继续深究,有兴趣看源码,这里返回的是一个handler } 上面代码很简单,mux.handler的实现是调用的mux.match函数对path进行匹配并返回handler的,这里就不深究了。 总结:1. 2. 3. 3. 4. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |