golang Http服务浅析

golang Http服务浅析,第1张

概述golang的HTTP包提供了了很强大的功能,开发人员即使不使用框架也可以很方便的进行开发。下面就简单说一下开发web应用时HTTP包都做了哪些工作。 我们在建立一个WEB应用的时候经常会这样使用: http.HandleFunc("/hello", func(writer http.ResponseWriter, request *http.Request) { writer.W

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方法,实现这个接口得有ServeMuxHandlerFuncconn也实现了,这里不介绍)。

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方法会调用ServeMuxServehttp方法进行路由。

总结

以上是内存溢出为你收集整理的golang Http服务浅析全部内容,希望文章能够帮你解决golang Http服务浅析所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/1269790.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-08
下一篇 2022-06-08

发表评论

登录后才能评论

评论列表(0条)

保存