zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    Largest Rectangle in Histogram
    Valid Sudoku
    Set Matrix Zeroes
    Unique Paths
    Binary Tree Level Order Traversal II
    Binary Tree Level Order Traversal
    Path Sum II
    Path Sum
    Validate Binary Search Tree
    新手程序员 e
  • 原文地址:https://www.cnblogs.com/xxswkl/p/14160704.html
Copyright © 2011-2022 走看看