Read Beego-routing mechanism (1)

Source: Internet
Author: User
This is a creation in Article, where the information may have evolved or changed.

Beego is a well-known Golang WEB framework based on the MVC model, which supports automatic routing and restful, and config,cache,session,orm modules can be used directly. The most important thing in MVC is routing. It implements the mapping from the Web request to the corresponding controller method. Typically, a route consists of three parts: adding Rules , parsing rules , and matching rules . Just I was divided into three parts to analyze the Beego routing implementation mechanism.

This article is the analysis of adding routing rules, where do you start? Beego has an open source forum system Wetalk, that is, golanghome implementation, from his routing began to look.

The Wetalk routing is very long and there are many controllers that need to be registered. From a simple perspective, I wetalk.go#l79:

posts := new(post.PostListRouter)beego.Router("/", posts, "get:Home")beego.Router("/:slug(recent|best|cold|favs|follow)", posts, "get:Navs")beego.Router("/category/:slug", posts, "get:Category")beego.Router("/topic/:slug", posts, "get:Topic;post:TopicSubmit")

General Routing

The method of registering a route is beego.Router(...) that the parameter is the URL rule, the Controller object, and his internal counterpart. How to use this method, you can refer to the official documents. How do you do it? Keep looking down, Beego.go:

func Router(rootpath string, c ControllerInterface, mappingMethods ...string) *App {BeeApp.Handlers.Add(rootpath, c, mappingMethods...)return BeeApp}

Hehe, the method falls on BeeApp.Hanlders . BeeApp.Hanldersis an *ControllerRegistor instance, corresponding to the Add method in Router.go:

Func (P *controllerregistor) Add (pattern string, C Controllerinterface, Mappingmethods ... string) {reflectval: = reflect. ValueOf (c) T: = reflect. Indirect (Reflectval). Type () Methods: = Make (map[string]string) if Len (mappingmethods) > 0 {semi: = strings. Split (Mappingmethods[0], ";") For _, V: = Range Semi {colon: = strings. Split (V, ":") If Len (colon)! = 2 {Panic ("method mapping format is invalid")}comma: = Strings. Split (Colon[0], ",") for _, M: = Range Comma {if _, OK: = Httpmethod[strings. ToUpper (m)]; m = = "*" | | OK {if Val: = Reflectval.methodbyname (Colon[1]); Val. IsValid () {methods[strings. ToUpper (m)] = Colon[1]} else {panic ("'" + colon[1] + "' method doesn ' t exist in the controller" + T.name ())}}} else {panic (V + "is an invalid method mapping. Method doesn ' t exist "+ m)}}}}route: = &controllerinfo{}route.pattern = Patternroute.methods = Methodsroute.routerty PE = Routertypebeegoroute.controllertype = Tif len (methods) = = 0 {For _, M: = Range HttpMethod {p.addtorouter (M, pattern, RouTE)}} else {for k, _: = Range methods {if k = = ' * ' {for _, M: = Range HttpMethod {p.addtorouter (M, Pattern, route)}} else {P.addtorouter (k, pattern, route)}}}}

A long, 1.1-point look:

The first step is to get the reflection type of the controller reflect.Type .

The second step, parsing mappingMethods , is beego.Router(...) the third parameter of the above code, for example get:Topic;post:TopicSubmit . The literal guess is the controller method name that corresponds to the HTTP request, like GET-postlistrouter.topic (). Semicolons divide multiple HTTP requests, colon-split HTTP requests, and corresponding controller methods. HTTPMETHODlimit the supported HTTP request mode, not the normal panic. *means to match all of them HTTPMETHOD . Use reflection to obtain a corresponding method to determine whether it is valid.

The third step, build controllerInfo{} , and add to the route. patternis the incoming URL rule, which has not yet been resolved. methodsis the mapping of the HTTP request mode to the Controller method in the parsed route parameters. Here's one routerTypeBeego , the identity controllerInfo{} is a generic route. There are routerTypeRESTFul also routerTypeHandler two kinds, which will be explained below.

Next, just look at what p.addToRouter(...) is a! Router.go:

func (p *ControllerRegistor) addToRouter(method, pattern string, r *controllerInfo) {if !RouterCaseSensitive {pattern = strings.ToLower(pattern)}if t, ok := p.routers[method]; ok {t.AddRouter(pattern, r)} else {t := NewTree()t.AddRouter(pattern, r)p.routers[method] = t}}

Finally saw--the NewTree() routing tree. The collection of all routing rules is actually one map[http_method]*Tree . For the implementation of the routing tree, we will read the next article in detail.

RESTful Routing

Beego There's a way beego.RESTRouter(...) . I thought this method was a RESTful type of routing, looking at source code discovery, or called beego.Router(...) . Looking for a bit, routerTypeRESTFul type of route that was originally in Router.go beego.AddMethod(...) :

func (p *ControllerRegistor) AddMethod(method, pattern string, f FilterFunc) {if _, ok := HTTPMETHOD[strings.ToUpper(method)]; method != "*" && !ok {panic("not support http method: " + method)}route := &controllerInfo{}route.pattern = patternroute.routerType = routerTypeRESTFulroute.runfunction = fmethods := make(map[string]string)if method == "*" {for _, val := range HTTPMETHOD {methods[val] = val}} else {methods[strings.ToUpper(method)] = strings.ToUpper(method)}route.methods = methodsfor k, _ := range methods {if k == "*" {for _, m := range HTTPMETHOD {p.addToRouter(m, pattern, route)}} else {p.addToRouter(k, pattern, route)}}}

Also generates a controllerInfo{} commit to the routing tree. The difference router.runfunction is, not the reflection type of the controller, is a function type FilterFunc . So where does this restful route work?

beego.Get(...)It is beego.AddMethod("get",...) . Similar beego.Post(...) , and beego.Put(...) so on. In other words, this is a class of routing that receives a function as a method for routing rules, rather than a controller.

HTTP Handler Routing

Beego also has a routerTypeHandler type of route, adding a method in beego.Handler(...) Router.go:

func (p *ControllerRegistor) Handler(pattern string, h http.Handler, options ...interface{}) {route := &controllerInfo{}route.pattern = patternroute.routerType = routerTypeHandlerroute.handler = hif len(options) > 0 {if _, ok := options[0].(bool); ok {pattern = path.Join(pattern, "?:all")}}for _, m := range HTTPMETHOD {p.addToRouter(m, pattern, route)}}

The generated controllerInfo{} time is used http.Handler , saved in the router.handler field. And the following is the way the HTTP request for this route is set to all supported methods.

Automatic routing

Automatic routing is an added hassle in order to simplify the registration of routes with controllers. According to the structure of the controller to automatically add rules, the specific place in the Router.go:

Func (P *controllerregistor) addautoprefix (prefix string, c controllerinterface) {reflectval: = reflect. ValueOf (c) RT: = Reflectval.type () CT: = reflect. Indirect (Reflectval). Type () Controllername: = Strings. Trimsuffix (Ct. Name (), "Controller") for I: = 0; I < Rt. Nummethod (); i++ {if!utils. Inslice (Rt. Method (i). Name, Exceptmethod) {route: = &controllerinfo{}route.routertype = Routertypebeegoroute.methods = map[string]string {"*": RT. Method (i). Name}route.controllertype = Ctpattern: = path. Join (prefix, strings. ToLower (controllername), strings. ToLower (Rt. Method (i). Name), "*") Patterninit: = path. Join (prefix, controllername, Rt. Method (i). Name, "*") Patternfix: = path. Join (prefix, strings. ToLower (controllername), strings. ToLower (Rt. Method (i). Name) Patternfixinit: = path. Join (prefix, controllername, Rt. Method (i). Name) Route.pattern = Patternfor _, M: = Range HttpMethod {p.addtorouter (M, pattern, route) P.addtorouter (M, Patterninit, RO Ute) P.addtorouter (M, Patternfix, route) P.addtorouter (m, patterNfixinit, Route)}}} 

Here the pattern is spliced according to the controller's method. The controller's built-in method is not processed first exceptMethod , and then, based on the controller's name and method, the case-sensitive registration prefix/controller/method/* and prefix/controller/method Two rules to all HTTP request methods.

Final

In general, the process of adding a route, summed up is added controllerInfo{} to the *Tree . controllerInfo{}The structure is:

type controllerInfo struct {pattern        stringcontrollerType reflect.Typemethods        map[string]stringhandler        http.Handlerrunfunction    FilterFuncrouterType     int}

As you can see, at this point the pattern--routing rule--has not yet been parsed. Only the method of HTTP request and corresponding call is recorded in the map of methods, or the method function of the call is saved directly in handler or runfunction.

So next, let's read the following controllerInfo{} procedure to add to *Tree . Since it is a routing tree, the hierarchy rules, node content, are important details.

Notice: This article is based on Beego v1.4.3

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.