How does ServeHTTP work?

前端 未结 5 825
温柔的废话
温柔的废话 2020-12-14 03:55

I am studying web development in Golang (Beginner) I came across some code I played around with and I\'m not too sure why it works, I looked through the library source code

相关标签:
5条回答
  • 2020-12-14 04:47

    Type declaration in this code for

    type foo int
    

    is implementing Handler interface. We can create struct or any type to implement ServeHTTP method. like

    type Foo struct{}
    func (m foo) ServeHTTP(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintln(w, "Some text")
    }
    

    For implementing Handler interface or any other interface It is been required to implement all methods declared in the interface on a type which is foo here.

    HandlerFunc is implementing ServeHttp method of Handler interface and hence can be passed to http.ListenAndServe as a handler. It can be used to create middlewares wrapping around ServeHttp.

    For more information on HanlderFunc use go doc in terminal

    godoc net/http HanlderFunc

    0 讨论(0)
  • 2020-12-14 04:49

    The relevant type in net/http is

    type Handler interface {
        ServeHTTP(ResponseWriter, *Request)
    }
    

    an interface type. Any concrete type implementing this interface can be used to serve HTTP request. Your bar is of type foo and foo implements the Handler interface. If the builtin HTTP server has to handle a request it will call the ServeHTTP method of your bar.

    0 讨论(0)
  • 2020-12-14 04:51

    I recommend going through these blog posts for anyone trying to understand about http.Handler
    A Recap of Request Handling in Go
    Making and Using HTTP Middleware

    0 讨论(0)
  • 2020-12-14 04:52

    Go's HTTP server takes in an address to listen on, and a handler. Internally, it creates a TCP listener to accept connections on the given address, and whenever a request comes in, it:

    1. Parses the raw HTTP request (path, headers, etc) into a http.Request
    2. Creates a http.ResponseWriter for sending the response
    3. Invokes the handler by calling its ServeHTTP method, passing in the Request and ResponseWriter

    The handler can be anything that satisfies the Handler interface, which your foo type does:

    type Handler interface {
        ServeHTTP(ResponseWriter, *Request)
    }
    

    The standard library also includes some conveniences, like HandlerFunc (which allows you to pass any func(ResponseWriter, *Request) and use it as a Handler) and ServeMux, which allows you to register many Handlers and choose which one handles which request based on the incoming request path.

    0 讨论(0)
  • 2020-12-14 04:54

    How does this exactly work? How is that ServeHTTP function being accessed?

    To answer this question we need to look how http.ListenAndServe works:

    func ListenAndServe(addr string, handler Handler) error {
        server := &Server{Addr: addr, Handler: handler}
        return server.ListenAndServe()
    }
    

    Here we create a Server with given address and handler and call the ListenAndServer method so let's take a look there:

    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)})
    }
    

    This method just starts listening given address and calls the Server method with our freshly created listener so let's follow the trail there:

    func (srv *Server) Serve(l net.Listener) error {
        defer l.Close()
    
        ...
    
        for {
            rw, e := l.Accept()
    
            ...
    
            c := srv.newConn(rw)
            c.setState(c.rwc, StateNew) // before Serve can return
            go c.serve(ctx)
        }
    }
    

    From the Serve method we can see that this is the point where we accept the new connection and start handling it in it's own goroutine.

    // Serve a new connection.
    func (c *conn) serve(ctx context.Context) {
        ...
        for {
            w, err := c.readRequest(ctx)
            ...
            serverHandler{c.server}.ServeHTTP(w, w.req)
            ...
        }
    }
    

    Here we finally call the ServeHTTP method but as we can see this is not yet our implementation of that function but something from the standard library so let's take a look what that serverHandler struct contains:

    // serverHandler delegates to either the server's Handler or
    // DefaultServeMux and also handles "OPTIONS *" requests.
    type serverHandler struct {
        srv *Server
    }
    
    func (sh serverHandler) ServeHTTP(rw ResponseWriter, req *Request) {
        handler := sh.srv.Handler
        if handler == nil {
            handler = DefaultServeMux
        }
        if req.RequestURI == "*" && req.Method == "OPTIONS" {
            handler = globalOptionsHandler{}
        }
        handler.ServeHTTP(rw, req)
    }
    

    So here it is finally. If we didn't provide any Handler the DefaultServeMux will be used but since we provided our foo handler ServeHTTP from foo get's called.

    And that's it. All of this can be found from server.go

    0 讨论(0)
提交回复
热议问题