Original link: http://youngxhui.top/2023/06/gin%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90%E4%B8%80/
The HTTP standard library explains how go’s standard library handles requests, but through the analysis of the source code, it can be found that the processing of this part of the standard library is relatively simple, for example, it does not support the parameters carried in the url. However, a large number of frameworks have appeared in the community to supplement the original http.
Most of Go’s HTTP frameworks are rewriting the routing part, which has achieved faster and more accurate route lookup, reduced the time consumed in the route parsing process, and improved the processing speed of the framework.
Standard Library HTTP Handling
Let’s first review the HTTP processing flow of the standard library.
-
Start the HTTP server: Use the http.ListenAndServe or http.ListenAndServeTLS function to start the HTTP server.
-
Handling the request: When the server receives an HTTP request, it uses the http.Handler implementation corresponding to the path to handle the request.
-
Call handler: The server will call
ServeHTTP
method and pass request-related information as parameters to the method. -
Route matching: In
ServeHTTP
method, a route matching the request is found by comparing the requested path with the registered routes. -
Call handler: If a matching route is found, the handler associated with that route is called.
-
Write response: The processing function writes response data through the
ResponseWriter
interface to return to the client.
According to the above processing method, there are currently two functions that need to be paid attention to: ServeHTTP
and ResponseWriter
. These are the two main approaches.
http.ListenAndServe
and http.ListenAndServeTLS
are used to start the HTTP server; and http.ResponseWriter
and http.Request
are used to write the response and process the request respectively.
At the same time, through source code analysis, if the handler is not passed in when listening, then the default handler of http, which is ServeMux
, will be used, so as long as we implement a Handler according to the standard, the original processing logic will be replaced, and the Handler’s The implementation is also very simple, as long as the interface ServeHTTP
is implemented.
gin start
Use gin to implement the simplest ping/pong service. Here is the example provided by the official README .
|
|
The implementation in the example is also very simple, first generate an engine through gin.Default()
. Then add related processing methods, and finally start with r.Run()
. The following will analyze the gin framework from the very beginning.
Engine
Default
is the first function used by gin. This function looks very simple, a total of five lines of code.
|
|
Engine
structure is mainly initialized through New()
function. In gin, it is managed through the structure of Engine
, which actually implements the method of ServeHTTP
.
Here, the function of Engine
is exactly the same as that of ServeMux
in the standard library, so its main function is to save the registered handler, and search and call it when it is used. Then let’s take a look at how routes and handlers are registered.
register route
In the above example, routes and handlers are registered via r.GET()
method. From the source code, it can be found that not only GET
method, but also other request methods, all of which directly call group.handler
method.
|
|
You can see from the code that this method is actually relatively simple. From the naming of the code, the following operations are basically performed: first calculate the absolute path, then merge the handlers, and finally add the route.
Why combine
In combineHandlers
method, first calculate the length of the current handlers
, and judge whether it exceeds the maximum length (the current maximum length is 63). If the maximum length is exceeded, a panic exception will be raised. Here, the source code uses two copy operations. The first time is to copy the data in group.Handlers
to mergedHandlers
, and the second time is to pass the data of handlers
into mergedHandlers
.
|
|
In this way, there are two parts of data in mergeHandler
. handlers
can be seen from the source code as handlers registered in the project. So what is in group.Handlers
?
In fact, it is the middleware registered when the project starts. In Default
method in Engine, we can see that engine.Use(Logger(), Recovery())
project registered two middlewares during initialization, and this Use
method is actually to add the middlewares to the above group.Handlers
In group.Handlers
, I won’t go into details here, but simply explain it. The specific middleware process will be described in the middleware (Middleware) chapter.
To be precise, the purpose of mergeHandlers
is to merge middleware and user-defined processing functions into a processing function slice, and register them in the route in a certain order.
add route
The route adding method is also relatively simple, and the core code is only 6 lines in total.
|
|
First get the root node of the tree through the request method, if the root node does not exist, create one, and finally add the relevant routes and handlers. How to add routes here, the route data structure will be explained in the Router chapter.
Up to now, the registration of routes has been completed.
how to run
After understanding how to start an http service in the net/http package of go in detail, in fact, looking back at gin now, everything has become very simple.
In the Run method of gin, it is mainly started by http.ListenAndServe
method of the standard library, and this method has been analyzed in detail in the HTTP standard library . The remaining method processes are basically the same as those in the standard library, except for the different One point is to replace the original default Handler with gin.Handler.
As I said before, if you want to become a Handler, you only need to implement ServeHTTP
method, and the gin engine
implements this method.
According to the previous processing flow of http, when gin receives relevant requests, it will call ServeHTTP
method uniformly. This method will process the received parameters, such as finding a suitable handler (Handler), and finally return the unified processing results.
|
|
The first variable used is pool
. The sync.Pool
type used by the pool here is mainly used to reuse Context
. Here, the Context is directly taken out from the pool, and some parameters of the Context are set, and finally engine.handleHTTPRequest
method is called.
This is also commonly used
engine.handleHTTPRequest
This method mainly handles the user’s HTTP request and determines the processing method of the request. In a nutshell: First, get the HTTP method (such as GET or POST) and URL path of the request, and decode the path if needed. It then searches the processing tree that matches the request. If it finds a matching node, it assigns the handler to the request’s context (c), and writes the HTTP response header. If no matching node is found, a “405 Method Not Allowed” or “404 Not Found” error response is written via serverError
.
This is basically the processing of a simple http request. You can see in the code that many things are actually handled by the context (Context).
This article is reproduced from: http://youngxhui.top/2023/06/gin%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90%E4%B8%80/
This site is only for collection, and the copyright belongs to the original author.