This article is the second in the gin source code analysis series. In this article, we mainly clarify a problem: how does a request return to gin to process logic after receiving the request through the net/http socket?
We still start with the example of net/http
func main() { http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("Hello World")) }) if err := http.ListenAndServe(":8000", nil); err != nil { fmt.Println("start http server fail:", err) } }
In this example, http.HandleFunc can see that the URI "/" is registered on defaultservermux by looking at the source code.
func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) { DefaultServeMux.HandleFunc(pattern, handler) }
Net / HTTP serverhttp
net/http has a very important Handler interface. Only when this method is implemented can the requested processing logic be introduced into its own processing flow.
// https://github.com/golang/go/blob/master/src/net/http/server.go#L86-L88 type Handler interface { ServeHTTP(ResponseWriter, *Request) }
The default defaultservermux implements this serverhttp
The flow process of this request:
-
After receiving the client request, socket.accept starts the go c.serve(connCtx) [net/http server.go:L3013] line to process the request. The server continues to wait for the client connection
-
Get the handler that can handle this request - > serverhandler . Serverhttp (W, w.req) [net / HTTP server. Go: l1952]
-
Jump to the real serverhttp to match the route and get the handler
-
Since there is no custom route, the default route [net/http server.go:L2880-2887] is used
-
Therefore, the defaultservermux is finally called to match the route, and the output returns the corresponding result
Explore the call link of gin serverhttp
The following is the official demo of gin. Just a few lines of code start an echo server.
package main import "github.com/gin-gonic/gin" func main() { r := gin.Default() r.GET("/ping", func(c *gin.Context) { c.JSON(200, gin.H{ "message": "pong", }) }) r.Run() // listen and serve on 0.0.0.0:8080 }
The general flow of this Code:
-
R: = gin. Default() initializes the relevant parameters
-
Register the route / ping and the corresponding handler in the route tree
-
Use r.Run() Start server
r. The bottom layer of run is still http.ListenAndServe
func (engine *Engine) Run(addr ...string) (err error) { defer func() { debugPrintError(err) }() trustedCIDRs, err := engine.prepareTrustedCIDRs() if err != nil { return err } engine.trustedCIDRs = trustedCIDRs address := resolveAddress(addr) debugPrint("Listening and serving HTTP on %s\n", address) err = http.ListenAndServe(address, engine) return }
Therefore, the process of establishing socket in gin, the process of accept ing client request is no different from that in net/http, and the above process will be repeated. The only difference is to get the location of ServeHTTP
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) }
sh.srv.Handler is of interface type, but its real type is gin.Engine. According to the dynamic forwarding characteristics of interface, it will eventually jump to the gin.Engine.ServeHTTP function.
Implementation of 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) }
So far, we have finally seen the whole picture of gin.ServeHTTP
-
Take a piece of memory from sync.pool
-
Initialize this memory to prevent data pollution
-
Handle request handleHTTPRequest
-
After the request is processed, return this memory to sync.pool
Now it seems that this implementation is very simple, but it is not. This is the first step for gin to process data, and it only flows requests into gin's processing flow.
Here's a conclusion: through the above source code process analysis, we know that the function net/http.ServeHTTP is very important. Only with the existence of this function can the request flow into the current Go frameworks. If you are interested, you can see how echo, iris, Go zero and other frameworks implement ServeHTTP.
For information on how gin matches routes and how to get handler s, please pay attention to the following articles. If you think the article is good, welcome to like + look again + forward.
Welcome to the official account. More learning materials sharing, attention to the official account reply order:
-
Reply to 0 and get the Go manual
-
Reply 1: get the Go source code flow chart