• http源码


    ServeHTTP函数调用在三个地方,它们三个都实现了Handler接口,

    一是serverHandler{c.server}.ServeHTTP(w, w.req),它是serverHandler调用的,里面有ListenAndServe初始化时生成的Server对象,因为Server中有注册的路由。

    二是handler.ServeHTTP(rw, req),handler是个接口对象,它绑定了注册的路由,在http中它是DefaultServeMux,在gin中它是Engine。

    三是h.ServeHTTP(w, r),h是个接口,这里绑定的是注册的路由函数,但注册的路由函数没有实现这个接口,所以在注册的时候进行了类型强转mux.Handle(pattern, HandlerFunc(handler)),在gin中没有调用这个,估计是不需要,

    1 分析以下代码

    package main
    import (
        "fmt"
        "log"
        "net/http"
    )
    func handleRequest(w http.ResponseWriter, r *http.Request) {
        fmt.Println("aaaaa")
    }
    func main() {
        // set route
        http.HandleFunc("/a/", handleRequest)
        fmt.Println("Listening at port 9090...")
        // listen at port 9090 and serve requests
        err := http.ListenAndServe(":9090", nil)
        if err != nil {
            log.Fatal("ListenAndServe: ", err)
        }
    }
    View Code

    2 http.HandleFunc路由的注册

    var DefaultServeMux = &defaultServeMux
    var defaultServeMux ServeMux
    // 传入的pattern是URL,handler是路由函数
    func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
        DefaultServeMux.HandleFunc(pattern, handler)
    }
    // 调用ServerMux的Handle方法注册路由,
    func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
        if handler == nil {
            panic("http: nil handler")
        }
        // 注意这里的进行了类型的强制转换,handler是传入的函数类型,HandlerFunc是自定义的类型它实现了ServeHTTP方法,所以实现了Handler接口
        mux.Handle(pattern, HandlerFunc(handler))
    }
    // 特别注意这里虽然传入的handler函数和这里定义的类型形式上一样,但它不是HandlerFunc类型,因为它没有实现ServeHTTP接口,
    type HandlerFunc func(ResponseWriter, *Request)
    func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
        f(w, r)
    }
    func (mux *ServeMux) Handle(pattern string, handler Handler) {
        mux.mu.Lock()
        defer mux.mu.Unlock()
        if pattern == "" {
            panic("http: invalid pattern")
        }
        if handler == nil {
            panic("http: nil handler")
        }
        if _, exist := mux.m[pattern]; exist {
            panic("http: multiple registrations for " + pattern)
        }
        if mux.m == nil {
            mux.m = make(map[string]muxEntry)
        }
        e := muxEntry{h: handler, pattern: pattern}
        // 注册的路由实际上就是个map,从这里也可以看出http的路由注册非常简单,所以有了后来的httprouter,
        mux.m[pattern] = e
        if pattern[len(pattern)-1] == '/' {
            mux.es = appendSorted(mux.es, e)
        }
        if pattern[0] != '/' {
            mux.hosts = true
        }
    }
    // m用于存储路由的url和其对应的处理函数,
    type ServeMux struct {
        mu    sync.RWMutex
        m     map[string]muxEntry
        es    []muxEntry // slice of entries sorted from longest to shortest.
        hosts bool       // whether any patterns contain hostnames
    }
    View Code

    3 http.ListenAndServe,监听端口,收到请求,处理请求,返回结果

    // 启动监听,Handler是个接口,它里面只有一个ServeHttp方法,直接用http包时,这个置为nil,
    func ListenAndServe(addr string, handler Handler) error {
        server := &Server{Addr: addr, Handler: handler}
        return server.ListenAndServe()
    }
    // 调用Server的Serve方法,
    func (srv *Server) ListenAndServe() error {
        if srv.shuttingDown() {
            return ErrServerClosed
        }
        addr := srv.Addr
        if addr == "" {
            addr = ":http"
        }
        ln, err := net.Listen("tcp", addr)
        if err != nil {
            return err
        }
        return srv.Serve(ln)
    }
    //
    func (srv *Server) Serve(l net.Listener) error {
        if fn := testHookServerServe; fn != nil {
            fn(srv, l) // call hook with unwrapped listener
        }
    
        origListener := l
        l = &onceCloseListener{Listener: l}
        defer l.Close()
    
        if err := srv.setupHTTP2_Serve(); err != nil {
            return err
        }
    
        if !srv.trackListener(&l, true) {
            return ErrServerClosed
        }
        defer srv.trackListener(&l, false)
    
        baseCtx := context.Background()
        if srv.BaseContext != nil {
            baseCtx = srv.BaseContext(origListener)
            if baseCtx == nil {
                panic("BaseContext returned a nil context")
            }
        }
    
        var tempDelay time.Duration // how long to sleep on accept failure
        ctx := context.WithValue(baseCtx, ServerContextKey, srv)
        for {
            rw, err := l.Accept()
            if err != nil {
                select {
                case <-srv.getDoneChan():
                    return ErrServerClosed
                default:
                }
                if ne, ok := err.(net.Error); ok && ne.Temporary() {
                    if tempDelay == 0 {
                        tempDelay = 5 * time.Millisecond
                    } else {
                        tempDelay *= 2
                    }
                    if max := 1 * time.Second; tempDelay > max {
                        tempDelay = max
                    }
                    srv.logf("http: Accept error: %v; retrying in %v", err, tempDelay)
                    time.Sleep(tempDelay)
                    continue
                }
                return err
            }
            connCtx := ctx
            if cc := srv.ConnContext; cc != nil {
                connCtx = cc(connCtx, rw)
                if connCtx == nil {
                    panic("ConnContext returned nil")
                }
            }
            tempDelay = 0
            c := srv.newConn(rw)
            c.setState(c.rwc, StateNew) // before Serve can return
            go c.serve(connCtx)
        }
    }
    // 上述for循环可简化为,
    for {
        rw, e := l.Accept() // 这里就是监听端口收到的请求,当收到请求后,建立新连接,
        ...
        c, err := srv.newConn(rw)
        ...
        go c.serve()  // 对新建的连接开启一个协程进行处理
    }
    // 注意在新连接生成的时候,将之前ListenAndServe中初始化的Server也保存在了里面,
    func (srv *Server) newConn(rwc net.Conn) *conn {
        c := &conn{
            server: srv,
            rwc:    rwc,
        }
        if debugServerConnections {
            c.rwc = newLoggingConn("server", c.rwc)
        }
        return c
    }
    // 调用serve处理收到的Request,
    func (c *conn) serve(ctx context.Context) {
        c.remoteAddr = c.rwc.RemoteAddr().String()
        ctx = context.WithValue(ctx, LocalAddrContextKey, c.rwc.LocalAddr())
        defer func() {
            if err := recover(); err != nil && err != ErrAbortHandler {
                const size = 64 << 10
                buf := make([]byte, size)
                buf = buf[:runtime.Stack(buf, false)]
                c.server.logf("http: panic serving %v: %v
    %s", c.remoteAddr, err, buf)
            }
            if !c.hijacked() {
                c.close()
                c.setState(c.rwc, StateClosed)
            }
        }()
        if tlsConn, ok := c.rwc.(*tls.Conn); ok {
            if d := c.server.ReadTimeout; d != 0 {
                c.rwc.SetReadDeadline(time.Now().Add(d))
            }
            if d := c.server.WriteTimeout; d != 0 {
                c.rwc.SetWriteDeadline(time.Now().Add(d))
            }
            if err := tlsConn.Handshake(); err != nil {
                // If the handshake failed due to the client not speaking
                // TLS, assume they're speaking plaintext HTTP and write a
                // 400 response on the TLS conn's underlying net.Conn.
                if re, ok := err.(tls.RecordHeaderError); ok && re.Conn != nil && tlsRecordHeaderLooksLikeHTTP(re.RecordHeader) {
                    io.WriteString(re.Conn, "HTTP/1.0 400 Bad Request
    
    Client sent an HTTP request to an HTTPS server.
    ")
                    re.Conn.Close()
                    return
                }
                c.server.logf("http: TLS handshake error from %s: %v", c.rwc.RemoteAddr(), err)
                return
            }
            c.tlsState = new(tls.ConnectionState)
            *c.tlsState = tlsConn.ConnectionState()
            if proto := c.tlsState.NegotiatedProtocol; validNextProto(proto) {
                if fn := c.server.TLSNextProto[proto]; fn != nil {
                    h := initALPNRequest{ctx, tlsConn, serverHandler{c.server}}
                    fn(c.server, tlsConn, h)
                }
                return
            }
        }
        // HTTP/1.x from here on.
        ctx, cancelCtx := context.WithCancel(ctx)
        c.cancelCtx = cancelCtx
        defer cancelCtx()
        c.r = &connReader{conn: c}
        c.bufr = newBufioReader(c.r)
        c.bufw = newBufioWriterSize(checkConnErrorWriter{c}, 4<<10)
        for {
            w, err := c.readRequest(ctx)
            if c.r.remain != c.server.initialReadLimitSize() {
                // If we read any bytes off the wire, we're active.
                c.setState(c.rwc, StateActive)
            }
            if err != nil {
                const errorHeaders = "
    Content-Type: text/plain; charset=utf-8
    Connection: close
    
    "
                switch {
                case err == errTooLarge:
                    const publicErr = "431 Request Header Fields Too Large"
                    fmt.Fprintf(c.rwc, "HTTP/1.1 "+publicErr+errorHeaders+publicErr)
                    c.closeWriteAndWait()
                    return
                case isUnsupportedTEError(err):
                    code := StatusNotImplemented
                    fmt.Fprintf(c.rwc, "HTTP/1.1 %d %s%sUnsupported transfer encoding", code, StatusText(code), errorHeaders)
                    return
                case isCommonNetReadError(err):
                    return // don't reply
                default:
                    publicErr := "400 Bad Request"
                    if v, ok := err.(badRequestError); ok {
                        publicErr = publicErr + ": " + string(v)
                    }
                    fmt.Fprintf(c.rwc, "HTTP/1.1 "+publicErr+errorHeaders+publicErr)
                    return
                }
            }
            req := w.req
            if req.expectsContinue() {
                if req.ProtoAtLeast(1, 1) && req.ContentLength != 0 {
                    // Wrap the Body reader with one that replies on the connection
                    req.Body = &expectContinueReader{readCloser: req.Body, resp: w}
                    w.canWriteContinue.setTrue()
                }
            } else if req.Header.get("Expect") != "" {
                w.sendExpectationFailed()
                return
            }
            c.curReq.Store(w)
            if requestBodyRemains(req.Body) {
                registerOnHitEOF(req.Body, w.conn.r.startBackgroundRead)
            } else {
                w.conn.r.startBackgroundRead()
            }
            serverHandler{c.server}.ServeHTTP(w, w.req)
            w.cancelCtx()
            if c.hijacked() {
                return
            }
            w.finishRequest()
            if !w.shouldReuseConnection() {
                if w.requestBodyLimitHit || w.closedRequestBodyEarly() {
                    c.closeWriteAndWait()
                }
                return
            }
            c.setState(c.rwc, StateIdle)
            c.curReq.Store((*response)(nil))
            if !w.conn.server.doKeepAlives() {
                return
            }
            if d := c.server.idleTimeout(); d != 0 {
                c.rwc.SetReadDeadline(time.Now().Add(d))
                if _, err := c.bufr.Peek(4); err != nil {
                    return
                }
            }
            c.rwc.SetReadDeadline(time.Time{})
        }
    }
    //对于同一个连接, 循环地执行读取请求, 处理请求, 完成请求三个操作
    for{
        w, err := c.readRequest()
        ...
        serverHandler{c.server}.ServeHTTP(w, w.req) // 这里直接初始化了一个serverHandler对象,
        ...
        w.finishRequest()
        ...
    }
    // rw req都是之前在readRequest中读取的,
    func (sh serverHandler) ServeHTTP(rw ResponseWriter, req *Request) {
        // serverHandler只有一个属性*Server,Server的属性Handler即之前http.ListenAndServer中传入的handler,
        // Server的属性Handler是接口Handler,它只有一个方法ServeHTTP,只要实现了ServeHTTP方法,就实现了Handler接口,
        if handler == nil {
            handler = DefaultServeMux
        }
        if req.RequestURI == "*" && req.Method == "OPTIONS" {
            handler = globalOptionsHandler{}
        }
        // 若handler接口绑定的类型为Engine,则ServeHTTP在gin中实现,
        handler.ServeHTTP(rw, req)
    }
    // 在gin中,上面的ServeHTTP会调用这个,
    func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {
        c := engine.pool.Get().(*Context)
        c.writermem.reset(w)
        c.Request = req
        c.reset()
        engine.handleHTTPRequest(c)
        engine.pool.Put(c)
    }
    // 在直接调用http包时,上面的handler接口绑定的类型是之前初始化的ServeMux对象
    func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) {
        if r.RequestURI == "*" {
            if r.ProtoAtLeast(1, 1) {
                w.Header().Set("Connection", "close")
            }
            w.WriteHeader(StatusBadRequest)
            return
        }
        // 在之前注册的ServeMux中找到URL对应的路由函数,
        h, _ := mux.Handler(r)
        h.ServeHTTP(w, r)
    }
    // 在Handler中调用了handler
    func (mux *ServeMux) handler(host, path string) (h Handler, pattern string) {
        mux.mu.RLock()
        defer mux.mu.RUnlock()
        if mux.hosts {
            h, pattern = mux.match(host + path)
        }
        if h == nil {
            h, pattern = mux.match(path)
        }
        if h == nil {
            h, pattern = NotFoundHandler(), ""
        }
        return
    }
    // match就是直接在map中寻找对应URL的路由函数,
    func (mux *ServeMux) match(path string) (h Handler, pattern string) {
        v, ok := mux.m[path]
        if ok {
            return v.h, v.pattern
        }
        for _, e := range mux.es {
            if strings.HasPrefix(path, e.pattern) {
                return e.h, e.pattern
            }
        }
        return nil, ""
    }
    // 上面返回的h类型是HandlerFunc,即type HandlerFunc func(ResponseWriter, *Request),
    // 因为之前在路由注册前进行类型强制转换,HanderFunc类型实现了Handler接口,所以这里可以直接调用,
    func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
        f(w, r)
    }
    View Code

    总体流程

    一 调用http.HandleFunc("/a/", handleRequest)按如下顺序执行:
    1 首先调用Http.HandleFunc,
    2 调用了DefaultServerMux的HandleFunc
    3 调用了DefaultServerMux的Handle,这里进行了类型的强转,因为传入的函数并没有实现ServeHTTP方法,
      往DefaultServerMux的map[string] muxEntry中增加对应的handler和路由规则。
    
    二 调用http.ListenAndServe(":9090",nil),按如下顺序执行:
    1 实例化Server。                        server := &Server{Addr: addr, Handler: handler}  Handler为实现了ServeHTTP的接口,
    2 调用Server的ListenAndServe()。        server.ListenAndServe()
    3 调用net.Listen("tcp",addr)监听端口。   ln, err := net.Listen("tcp", addr)
    4 启动一个for死循环,在循环体中监听请求。    rw, err := l.Accept()
    5 一旦收到请求,对该请求实例化一个Conn,并且开启一个goroutine为这个请求进行服务go c.serve()。  c := srv.newConn(rw)  go c.serve(connCtx)
    6 在c.serve()中仍是启动一个for死循环,读取请求的内容。readRequest是读取数据,解析请求的地方,包括解析请求的header、body,和一些基本的校验,
      比如header头信息,请求method等          w, err := c.readRequest(ctx)
    7 调用业务层定义的路由,调用最开始在http.ListenAndServe中实例化的Server,它也实现了Handler接口,并将处理好的Request、Response对象作为参数传入
      serverHandler{c.server}.ServeHTTP(w, w.req)
    8 在Server的ServeHTTP中,将handler设置为1中的handler,若为nil设置为DefaultServeMux
      handler := sh.srv.Handler    if handler == nil {handler = DefaultServeMux}
    9 调用handler的ServeHttp。              handler.ServeHTTP(rw, req)
    10在之前注册的路由中找到处理请求的路由函数,  h, _ := mux.Handler(r)
    11如果找到了路由函数,调用这个路由handler的ServeHttp。    h.ServeHTTP(w, r)
      否则返回"404 page not found"return HandlerFunc(NotFound)
    View Code

    参考:https://james-yip.github.io/2017/11/16/go-http-src-analysis/

    https://www.huweihuang.com/golang-notes/web/golang-http-execution-flow.html

    https://www.shipengqi.top/2019/11/12/go-http-resouce-code-analysis/

    https://zhuanlan.zhihu.com/p/101995755

  • 相关阅读:
    【BZOJ3533】向量集(SDOI2014)-线段树+凸壳+二分
    【BZOJ4869】相逢是问候(六省联考2017)-扩展欧拉定理+线段树
    【BZOJ4012】开店(HNOI2015)-动态点分治+set
    【BZOJ1095】捉迷藏(ZJOI2007)-动态点分治+堆
    【BZOJ2299】向量(HAOI2011)-裴蜀定理
    【BZOJ4942】整数(NOI2017)-线段树+压位
    【BZOJ3594】方伯伯的玉米田(SCOI2014)-DP+二维树状数组
    背包DP专题
    【2018.11.7】【luoguNOIp 热身赛】解题报告及总结
    【一天一DP计划】状压DP
  • 原文地址:https://www.cnblogs.com/xxswkl/p/14160704.html
Copyright © 2020-2023  润新知