golang的Http包提供了了很强大的功能,开发人员即使不使用框架也可以很方便的进行开发。下面就简单说一下开发web应用时Http包都做了哪些工作。
我们在建立一个WEB应用的时候经常会这样使用:
http.HandleFunc("/hello",func(writer http.ResponseWriter,request *http.Request) { writer.Write([]byte("hello")) }) http.ListenAndServe(":8080",nil)
这样我们访问8080
端口就会打印hello
。
下面从两个介绍http的工作流程:
1.handler注册过程
2.服务器监听过程
3.当我们访问接口时服务器的处理过程。
注册的代码是:
http.HandleFunc("/hello",request *http.Request) { writer.Write([]byte("hello")) })
看一下http.HandleFunc
函数:
var DefaultServeMux = &defaultServeMuxvar defaultServeMux ServeMuxfunc 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中。
这里可以发现HandleFunc函数中会把handler强制转换为HandlerFunc类型:HandlerFunc(handler)。
来看看HandleFunc类型。
type HandlerFunc func(ResponseWriter,*Request)func (f HandlerFunc) Servehttp(w ResponseWriter,r *Request) { f(w,r)}
HandlerFunc和我们传入的Handler的函数签名是一样的,只是它还有一个Servehttp函数,这个函数会调用我们传入的handler。可以看出HandlerFunc只是对我们传入的handler进行了包装并提供Servehttp来调用handler
。
这里总结一下注册handler的流程:
1.http.HandlerFunc调用ServeMux. HandleFunc方法。
2.ServeMux. HandleFunc首先对我们传进来的handler强制转换为HandlerFunc类型(目的是提供Serverhttp接口来执行我们传进来的Handler),然后调用ServeMux. Handle方法。
3.ServeMux. Handle方法会把path和handler存在ServeMux结构的m
字段中(使用map的形式存放)。
调用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方法来等待请求的到来。
总结一下:
1.http.ListenAndServe
创建Server
类型变量并调用Server.ListenAndServe
方法。
2.Server.ListenAndServe
方法首先会监听TCP
端口并调用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接口的实现的实现是用来干什么的呢?这里可以直接给出答案:是用来做路由的。
看一下ServerMux的Servehttp函数:
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.Handler
接口:
包含Servehttp
方法,实现这个接口得有ServeMux
和HandlerFunc
(conn
也实现了,这里不介绍)。
2.ServeMux
结构体:
1.1 它的m
字段用于存储我们注册的handler
1.2 它实现了Handler
接口,它的Servehttp
方法提供了路由功能。
3.HandlerFunc
结构体:
它实现了Handler
接口,我们编写的handler
都会被转换为HandlerFunc
类型,它的Servehttp
方法会执行我们注册的handler
。
3.Server
结构体:
监听指定端口,当请求到达的时候创建一个conn
对象并执行它的Servehttp
方法。
4.conn
结构体:
一个conn
代表一个连接,它的Servehttp
方法会调用ServeMux
的Servehttp
方法进行路由。
以上是内存溢出为你收集整理的golang Http服务浅析全部内容,希望文章能够帮你解决golang Http服务浅析所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)