Discussion on the use and implementation of go restful Framework
- 2020-06-12 09:30:04
- OfStack
REST (Representational State Transfer) is a widely used method to realize synchronous communication between distributed nodes in recent years. REST principle describes one interaction form of ES6en-ES7en in the network, that is, URL locates resources, and HTTP method describes the interaction form of operations. If the network interface for interactions between CS satisfies the REST style, it is called RESTful API. Here are the REST principles for understanding the RESTful architecture summary:
Resources on the network are identified by URI 1. Passing between client and server, some representation of this resource. The presentation layer can be json, text, base 2, or images. Through the four verbs of HTTP, the client operates on the server resources to achieve the state transformation of the presentation layer.The reason why we want to design API of RESTful is that we use the data operation interface of HTTP's operating system 1 to limit URL as a resource, that is, each request is corresponding to a certain operation of a resource. This stateless design can realize the decoupling and separation of ES25en-ES26en and ensure the horizontal expansion capability of both ends of the system.
go-restful
go is package for building REST Web Services Google Go. go-restful defines Container WebService and Route3 important data structures.
Route represents one route and contains URL/HTTP/I/O type/callback handler RouteFunction WebService represents a service consisting of multiple Route that share the same Root as one Path Container represents a server, consisting of multiple WebService and one ES63en.ServerMux, distributed using RouteSelectorIn the simplest use case, register the route to WebService, add WebService to Container, and distribute it by Container.
func main() {
ws := new(restful.WebService)
ws.Path("/users")
ws.Route(ws.GET("/").To(u.findAllUsers).
Doc("get all users").
Metadata(restfulspec.KeyOpenAPITags, tags).
Writes([]User{}).
Returns(200, "OK", []User{}))
container := restful.NewContainer().Add(ws)
http.ListenAndServe(":8080", container)
}
container
container is written according to the router ServeMux of the standard library http, and it implements the Handler interface through the routing table of ServeMux. Please refer to the previous implementation of THE HTTP protocol and Go.
type Container struct {
webServicesLock sync.RWMutex
webServices []*WebService
ServeMux *http.ServeMux
isRegisteredOnRoot bool
containerFilters []FilterFunction
doNotRecover bool // default is true
recoverHandleFunc RecoverHandleFunction
serviceErrorHandleFunc ServiceErrorHandleFunction
router RouteSelector // default is a CurlyRouter
contentEncodingEnabled bool // default is false
}
func (c *Container)ServeHTTP(httpwriter http.ResponseWriter, httpRequest *http.Request) {
c.ServeMux.ServeHTTP(httpwriter, httpRequest)
}
Add WebService to Container, webServices for internal maintenance cannot have duplicate RootPath,
func (c *Container)Add(service *WebService)*Container {
c.webServicesLock.Lock()
defer c.webServicesLock.Unlock()
if !c.isRegisteredOnRoot {
c.isRegisteredOnRoot = c.addHandler(service, c.ServeMux)
}
c.webServices = append(c.webServices, service)
return c
}
Added to container and registered to mux is the function dispatch, which is responsible for distribution according to the rootPath of the different WebService.
func (c *Container)addHandler(service *WebService, serveMux *http.ServeMux)bool {
pattern := fixedPrefixPath(service.RootPath())
serveMux.HandleFunc(pattern, c.dispatch)
}
webservice
Each group of webservice represents one service sharing rootPath, where rootPath is set through ES109en.Path ().
type WebService struct {
rootPath string
pathExpr *pathExpression
routes []Route
produces []string
consumes []string
pathParameters []*Parameter
filters []FilterFunction
documentation string
apiVersion string
typeNameHandleFunc TypeNameHandleFunction
dynamicRoutes bool
routesLock sync.RWMutex
}
The routes registered through Route ultimately constitute the Route structure, which is added to WebService's routes.
func (w *WebService)Route(builder *RouteBuilder)*WebService {
w.routesLock.Lock()
defer w.routesLock.Unlock()
builder.copyDefaults(w.produces, w.consumes)
w.routes = append(w.routes, builder.Build())
return w
}
route
By constructing Route information from RouteBuilder, Path combines rootPath and subPath. Function is the route Handler, or processing function, which is added via ws.Get (subPath).To (function). Filters implements something like the gRPC interceptor, which is also similar to ES138en-ES139en's chain.
type Route struct {
Method string
Produces []string
Consumes []string
Path string // webservice root path + described path
Function RouteFunction
Filters []FilterFunction
If []RouteSelectionConditionFunction
// cached values for dispatching
relativePath string
pathParts []string
pathExpr *pathExpression
// documentation
Doc string
Notes string
Operation string
ParameterDocs []*Parameter
ResponseErrors map[int]ResponseError
ReadSample, WriteSample interface{}
Metadata map[string]interface{}
Deprecated bool
}
dispatch
The main function of the server side is routing and distribution. http package implements one ServeMux, go-restful encapsulates multiple services on this basis, how to distribute routes to webservice from container, and then to specific processing functions by webservice. This is all done in dispatch.
SelectRoute select matching WebService and matching Route from the registered WebService based on Req. Where the routing selector defaults to CurlyRouter. Parse pathParams and process the request for wrap and the corresponding handler to the routing. If there is an filters definition, then chain processing.
func (c *Container)dispatch(httpWriter http.ResponseWriter, httpRequest *http.Request) {
func() {
c.webServicesLock.RLock()
defer c.webServicesLock.RUnlock()
webService, route, err = c.router.SelectRoute(
c.webServices,
httpRequest)
}()
pathProcessor, routerProcessesPath := c.router.(PathProcessor)
pathParams := pathProcessor.ExtractParameters(route, webService, httpRequest.URL.Path)
wrappedRequest, wrappedResponse := route.wrapRequestResponse(writer,
httpRequest, pathParams)
if len(c.containerFilters)+len(webService.filters)+len(route.Filters) > 0 {
chain := FilterChain{Filters: allFilters, Target: func(req *Request, resp *Response) {
// handle request by route after passing all filters
route.Function(wrappedRequest, wrappedResponse)
}}
chain.ProcessFilter(wrappedRequest, wrappedResponse)
} else {
route.Function(wrappedRequest, wrappedResponse)
}
}
go-chassis
rest-server the ES173en-server implementation is a 1-layer encapsulation on ES175en-restful. At the time of Register, the registered schema should be resolved into routes and registered in webService. When Start starts server, container. Add(r. ws), and at the same time, container will be handed to ES189en. Server and finally start ListenAndServe.
type restfulServer struct {
microServiceName string
container *restful.Container
ws *restful.WebService
opts server.Options
mux sync.RWMutex
exit chan chan error
server *http.Server
}
According to Method, handle of different methods is registered with WebService, and routes information read from schema includes Method, Func and PathPattern.
type Container struct {
webServicesLock sync.RWMutex
webServices []*WebService
ServeMux *http.ServeMux
isRegisteredOnRoot bool
containerFilters []FilterFunction
doNotRecover bool // default is true
recoverHandleFunc RecoverHandleFunction
serviceErrorHandleFunc ServiceErrorHandleFunction
router RouteSelector // default is a CurlyRouter
contentEncodingEnabled bool // default is false
}
0
It's really quite simple, so I won't write it. I'm so sleepy today.
legacy
Use, Reflection and performance of reflect in routing registration route select how to ensure the processing speed when it comes to fuzzy matching pathParams analytical