Transform the Httprouter to support the middleware
Source: Internet
Author: User
This is a creation in Article, where the information may have evolved or changed. # transform Httprouter make IT Support middleware # # written in front ' httprouter ' in the industry is widely acclaimed, mainly because of its performance ' Httprouter ' Project address: [Httprouter] (https://github.com/ Julienschmidt/httprouter) ' Httprouter ' principle: [click here to click here] (http://www.okyes.me/2016/05/08/httprouter.html) and ' Httprouter ' The default is not to support middleware and other features of the ' README ' said: ' Where can I find middleware X? This is just provides a very efficient request router with a few extra features. The router is just a HTTP. Handler, you can chain any HTTP. Handler compatible middleware before the router, for example the Gorilla handlers. Or you could just write your own, it's very easy! ' and I'm writing the bingo framework is also based on ' httprouter ', so prepare to retrofit it and let him support the functionality of the middleware my project address [silsuer/ Bingo] (Https://github.com/silsuer/bingo) # # starts to retrofit 1. Principle View Httprouter Source code, you can see, it uses a prefix tree to manage the registered route, and mount to this tree, is a ' Handle ' type method, this method long such ' type Handle func (http. Responsewriter, *http. Request, Params) ' using ' Httprouter. The Handle (args) ' method places the route in the tree according to the path, and when each HTTP request comes in, it goes to the ' servehttp ' method, which is a multi-path router with the following code: ' Go func ' (R *router) Servehttp (w http. Responsewriter, req *htTp. Request) {//Judgment panic function if r.panichandler! = nil {defer r.recv (W, req)}//start to find the registered route function if root: = R.trees[req. Method]; Root! = Nil {path: = req. Url. Path if handle, PS, TSR: = Root.getvalue (path); Handle! = Nil {//check found, execute this function handle (W, req, PS) return} else if req. Method! = "CONNECT" && path! = "/" {//not found, start redirection or other operation code: = 301//Permanent Redirect, request with GET met Hod if req. Method! = "GET" {///temporary redirect, request with same method//As of Go 1.3, go does not support status code 308. Co de = 307} If TSR && R.redirecttrailingslash {if Len (path) > 1 && path[len (PATH)-1] = = '/' {req. Url. Path = Path[:len (path)-1]} else {req. Url. Path = path + "/"} http. Redirect (W, req, req. Url. String (), code) return}//Try to fix the request path if R.redirectfixedpath {fixedpath, found: = Root.findcaseinsensit Ivepath (CleanPath (path), R.redirecttrailingslash,) if found {req. Url. Path = string (Fixedpath) http. Redirect (W, req, req. Url. String (), code) Return}}}//Handle 405 if r.handlemethodnotallowed {for method: = Range R.trees {//Skip the requested met Hod-we already tried this one if method = = Req. Method {Continue} handle, _, _: = R.trees[method].getvalue (req. Url. Path) if handle! = Nil {if r.methodnotallowed! = Nil {r.methodnotallowed (W, req)} else {http. Error (W, http. StatusText (http. statusmethodnotallowed), HTTP. Statusmethodnotallowed}}}}//If the NotFound function is defined, the function will be executed when the lookup is unsuccessful, otherwise the default NotFound method//Handle 404 If R.notfou nd! = nil {r.notfound (W, req)} else {http. NotFound (W, req)}} "and the so-called middleware, is to find the success of the first implementation of the middleware method, and then execute the handle method, then our idea is no longer on the tree to mount the handle method, but to mount a custom structure of our body, When the search succeeds, first look at whether the structure has middleware if there is execution, if not, directly execute the handle method 2. Customizing the structure of the two articles I wrote before [using go to write a simple MVC web Framework] (https://studygolang.com/articles/12818) [use go to encapsulate a handy orm] (https:// studygolang.com/articles/12825) also introduced, our routing structure is this: "Go type route struct {path string//Path Target Handle///corresponding Controller path C Ontroller@index such a method string//access typeIs the alias of Get Post or other alias string//route, and there is no egg to look like .... Middleware []handle///Middleware name} ' where Handle is using the method defined above ' Httprouter ', let's change the struct ' go/context struct ' type context struct {W Riter http. Responsewriter//Responds to Request *http. Request//requested params params//parameter} type TargetHandle func (context *context) type Middlewarehandle func (context *context) * Context//middleware needs to return the contexts to pass in the TargetHandle type Route struct {path string//Path Target TargetHandle//method to execute Stri ng//access type is the alias of Get Post or other alias string//route, and there is no egg like .... Middleware []middlewarehandle///Middleware name, method executed before execution of TargetHandle} "" We loaded the original handle parameters into a context structure and then indicated the type of the function in the route struct body. 3. Mount the route structure to the tree to view the method of registering the route ' httprouter ': ' Go func (R *router) Handle (method, path string, Handle Handle) {//Determine the path of the grid If the type is correct if path[0]! = '/' {panic ("path must begin with '/' in path '" + Path + "')}//If the prefix tree is empty, create a new if R.trees = = Nil { R.trees = Make (Map[string]*node)} root: = R.trees[method]//If the root node of the tree is empty, create a new root node if Root = nil {root = nEW (node) r.trees[method] = root}//Depending on the path, mount the method to be executed onto the tree Root.addroute (path, handle)} "" Now we're going to change the handle type of data into our own rout E type, very simple, the code is not posted, want to see see [Commit Change Record] (https://github.com/silsuer/bingo/commit/ b651757e328b9a711ad2fe274ece8326c954d762) Next change the entire tree file, in effect, the ' tree ' in the ' node ' structure of ' handle ' changed to a route and then use the tree file ' Handle ' place, are used ' n.route.target ' instead, although there is no brain operation, but to change a lot of lines also do not stick code ... commit record here ... [Commit change Record] (https://github.com/silsuer/bingo/commit/b651757e328b9a711ad2fe274ece8326c954d762) After the change of ' servehttp ' is such a drop ~ ' Go Func (R *router) servehttp (w http. Responsewriter, req *http. Request) {if r.panichandler! = nil {defer r.recv (W, req)}//Before looking, to see if there is a middleware//registration route, you should put the middleware here//start to find the registered route function I F Root: = R.trees[req. Method]; Root! = Nil {path: = req. Url. Path if route, PS, TSR: = Root.getvalue (path); Route. Target! = Nil {//package Context: = &context{w,req,ps}//execute the target function route. Target (context) return} else if req. Method! = "CONNECT" && path! = "/" {code: = 301//Permanent Redirect, request witH GET method if req. Method! = "GET" {///temporary redirect, request with same method//As of Go 1.3, go does not support status code 308. Co de = 307} If TSR && R.redirecttrailingslash {if Len (path) > 1 && path[len (PATH)-1] = = '/' {req. Url. Path = Path[:len (path)-1]} else {req. Url. Path = path + "/"} http. Redirect (W, req, req. Url. String (), code) return}//Try to fix the request path if R.redirectfixedpath {fixedpath, found: = Root.findcaseinsensit Ivepath (CleanPath (path), R.redirecttrailingslash,) if found {req. Url. Path = string (Fixedpath) http. Redirect (W, req, req. Url. String (), code) Return}}}}//Handle 405 if r.handlemethodnotallowed {for method: = Range R.trees {//Skip the Reque Sted Method-we already tried this one if method = = Req. Method {Continue} route, _, _: = R.trees[method].getvalue (req. Url. Path) if route. Target! = Nil {if r.methodnotallowed! = Nil {r.methodnotallowed (W, req)} else {http. Error (W, http. StatusText (http. StatusmethodnotAllowed), HTTP. Statusmethodnotallowed,)} Return}}}//Handle 404 if r.notfound! = Nil {r.notfound (W, req)} else {http. NotFound (W, req)}} "can see that after finding the node, I encapsulated a ' Context ', followed by the TargetHandle method, 4. Change code, Support middleware: ' Go/package context: = &c ONTEXT{W,REQ,PS}//Determine if the route has a middleware list, and if so, execute if Len (route. Middleware)!=0{for _,middlehandle:= range route. middleware{context = Middlehandle (context)//sequential execution middleware, the resulting return result is re-injected into context}}}//execute the target function route. Target (context) Return "Now, we define one of the following routes: ' go var R = []bingo. route{{Path: "/Home", Method:bingo. GET, Target:home. Index, middleware: []bingo. middlewarehandle{home. M1, home. M2,},},} ', where index,m1,m2 is defined as follows: ' Go func M1 (c *bingo. Context) *bingo. Context {fmt. Fprintln (C.writer, "This is Middleware 1") return C} func M2 (c *bingo. Context) *bingo. Context {fmt. Fprintln (C.writer, "This is Middleware 2") return C} func Index (c *bingo. Context) {fmt. Fprint (C.writer, "Hello World")} "and then execute ' Go run start.go ', browser access ' localhost:12345 ', you can see the success of the middleware implementation of the trace, the success of the transformation bingo! Welcome to star, Welcome to Pr~~~~484 Times Click
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