HTTP processing
Gin is written based on GO's net/http library, which is naturally concurrent. Running the function Engine.run() calls the ListenAndServe function of the net/http Library:
func (engine *Engine) Run(addr ...string) (err error) { defer func() { debugPrintError(err) }() address := resolveAddress(addr) debugPrint("Listening and serving HTTP on %s\n", address) err = http.ListenAndServe(address, engine) return }
ListenAndServe will call the serverhttp method in the Handler interface for each request:
type Handler interface { ServeHTTP(ResponseWriter, *Request) } func ListenAndServe(addr string, handler Handler) error
The Handler interface is implemented by Gin, and the content is not complicated. First, the Context context is constructed, then the handleHTTPRequest method is used to find the handler matching and matching with the Request path (handleHTTPRequest method also executes handler of the middleware. This method is the core method introduced in this article, see below). As follows:
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) }
Context
In the above, handlehtttprequest passes in the Context. What is its role?
A: it actually encapsulates some functions and stores HTTP context information such as request path, parameter and type. It will be passed to the user-defined request processing function. Users can use it to have many convenient functions. For example, it encapsulates the content type when returning. If you want to return Json body, you only need to call c.JSON(status, bodyContent) to avoid writing a lot of code.
type Context struct { writermem responseWriter Request *http.Request Writer ResponseWriter Params Params // Middleware execution function + user execution function handlers HandlersChain // The subscript of handlers to determine which execution function is currently being called index int8 engine *Engine ... }
middleware
What is middleware? How does Gin load middleware?
What is middleware
- Non business technical components are called middleware, and mongo, mysql, redis, mongoDriver and GoORM can all be called middleware.
- Gin's middleware is relatively narrow. Through the source code, it is found that its middleware only performs custom processing before and after the request. Gin also has many middleware, such as logrus and jwt.
Gin loading Middleware
Add the middleware processing function to the path group by calling the Use method of Engine, that is, to the Handlers slice of RouterGroup:
func (engine *Engine) Use(middleware ...HandlerFunc) IRoutes { engine.RouterGroup.Use(middleware...) ... return engine } func (group *RouterGroup) Use(middleware ...HandlerFunc) IRoutes { group.Handlers = append(group.Handlers, middleware...) return group.returnObj() }
Execution of Middleware
Here, the middleware has been added to the handlers of the RouterGroup. When will it be called?
In fact, the handlehtttprequest method mentioned above is the place to call the middleware. First, the code and then discuss:
func (engine *Engine) handleHTTPRequest(c *Context) { // something ... t := engine.trees for i, tl := 0, len(t); i < tl; i++ { if t[i].method != httpMethod { continue } root := t[i].root // handlers slice = execution function of each middleware + request processing function. handlers, params, tsr := root.getValue(rPath, c.Params, unescape) if handlers != nil { c.handlers = handlers c.Params = params c.Next() c.writermem.WriteHeaderNow() return } // something ... } // something ... } func (c *Context) Next() { c.index++ for c.index < int8(len(c.handlers)) { c.handlers[c.index](c) c.index++ } }
Through Next(), we can see that the processing functions of each middleware will be executed in turn, and the request processing function is added to the handlers at last, which is the last execution. In this way, the middleware custom processing is executed before the request processing function is executed.
What should I do if I want to execute the custom processing of the middleware after the request processing function is executed? The middleware can call the Next() function of the Context itself to realize: the logic before Next() in the middleware is executed before the request processing function; The logic after next () is executed after the request processing function.
(just transferred from Java to Go, learn together and make progress together. I think I can praise some achievements. If there is anything wrong, thank you for leaving a message)