Overview of rest framework
Let by go-zero
tool comes with a command line goctl
to generate a api service
, its main
function is as follows:
func main() {
flag.Parse()
var c config.Config
conf.MustLoad(*configFile, &c)
ctx := svc.NewServiceContext(c)
server := rest.MustNewServer(c.RestConf)
defer server.Stop()
handler.RegisterHandlers(server, ctx)
fmt.Printf("Starting server at %s:%d...\n", c.Host, c.Port)
server.Start()
}
- Parse the configuration file
serviceContext
configuration file and initialize 06168d29c2d409- Initialize
rest server
context
intoserver
:- Register routing
- the
context
the startendpoint
simultaneously injected intorouter
which
- Start
server
Next, we will explain its design principles step by step! Let's Go!
web framework
From the daily development experience, a good web framework roughly needs to meet the following characteristics:
- Route matching/multi-route support
- Support custom middleware
- The framework and business development are completely decoupled, making it convenient for developers to develop quickly
- Parameter verification/matching
- Service self-checking functions such as monitoring/logging/indicator
- Service self-protection (fuse/current limit)
go-zero rest design
https://github.com/zeromicro/go-zero/tree/master/rest
Overview
- With the help of context (different from gin's context), initialize the resource → save it in
serviveCtx
and share it in the handler (as for resource pooling, hand it over to the resource to handle it,serviveCtx
is just the entry and sharing point) - Independent router declaration file, also joins the concept of router group, which is convenient for developers to organize the code structure
- Several built-in middleware: monitoring/fuse/authentication, etc.
- Using goctl codegen + option design pattern , it is convenient for developers to control the access of some middleware.
The above figure describes the mode of rest processing requests and most of the processing paths.
- The built-in middleware of the framework has helped developers solve most of the logic of service self-processing
- At the same time, go-zero also gives developers out-of-the-box components (dq, fx, etc.)
business logic
- From the development mode to help developers only need to pay attention to their own
business logic
and the required resource preparation
Let us elaborate on how the rest is started?
Start the process
The figure above describes the modules and general flow of the overall server startup. Prepare to analyze the rest implementation according to the following process:
- Package and transformation based on http.server: engine (web framework core) and option
- Multi-route matching adopts radix-tree structure
- The middleware adopts the onion model →
[]Middleware
- http parse parsing and matching verification →
httpx.Parse()
createMetrics()
) and monitoring points (prometheus) will be collected during the request process
server engine package
Click on the big picture to watch
Engine runs through the entire server life cycle:
- The router will carry the path/handler defined by the developer, in the final router.handle()
- Registered custom middleware + framework middleware, executed before router handler logic
is here: the granularity of go-zero processing is on the route, and the encapsulation and processing are performed layer by layer on the route
Route matching
So when the request comes, how do you get to the routing layer in the first place?
First of all, in the development of the most primitive http server, there is such a piece of code:
type helloHandler struct{}
func (h *helloHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello, world!"))
}
func main() {
http.Handle("/", &helloHandler{})
http.ListenAndServe(":12345", nil)
}
http.ListenAndServe()
will be executed internally to: server.ListenAndServe()
Let's see how it is used in rest:
The incoming handler is actually the router generated by router.NewRouter(). This router carries the processing function set of the entire server.
At the same time, when the http.Server structure is initialized, the handler is injected into it:
type Server struct {
...
Handler Handler
}
func start(..., handler http.Handler, run func(srv *http.Server) error) (err error) {
server := &http.Server{
Addr: fmt.Sprintf("%s:%d", host, port),
Handler: handler,
}
...
return run(server)
}
After http.Server receives req, the final execution is: handler.ServeHTTP(rw, req)
So the built-in router also needs to implement ServeHTTP
. As for how the router itself implements ServeHTTP
: it is nothing more than finding a matching route, and then executing the handle logic corresponding to the route.
Parsing parameters
Parsing parameters is the basic ability that the http framework needs to provide. In the code generated by goctl code gen, the handler layer has integrated the req argument parse function:
// generate by goctl
func QueryAllTaskHandler(ctx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
// custom request in .api file
var req types.QueryAllTaskRequest
// parse http request
if err := httpx.Parse(r, &req); err != nil {
httpx.Error(w, err)
return
}
l := logic.NewEventLogic(r.Context(), ctx)
resp, err := l.QueryAllTask(req)
baseresponse.FormatResponseWithRequest(resp, err, w, r)
}
}
Enter httpx.Parse()
, mainly analyze the following pieces:
https://github.com/zeromicro/go-zero/blob/master/rest/httpx/requests.go#L32:6
- Parse path
- Parse the form
- Parse the http header
- Parse json
The function parameter check in Parse() is as follows:
https://go-zero.dev/cn/api-grammar.html in
tag modifier
Tips
To learn the source code, it is recommended to fork. You can deepen your understanding when you come out and read and write comments and experiences. You can also look back when you use this feature in the future.
project address
https://github.com/zeromicro/go-zero
Welcome to use go-zero
and star support us!
WeChat Exchange Group
Follow the " Practice " public account and click on the exchange group get the community group QR code.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。