This is a creation in Article, where the information may have evolved or changed.
Go Language Classic library usage analysis, not to be continued, welcome to sweep code attention flysnow_org
to the public number or website http://www.flysnow.org/, the first time to see the following series. If you feel helpful, share it with your friends and thank you for your support.
Previous Go Language Classic library usage analysis (v) | Negroni Middleware (i) introduces the use of Negroni intermediate and some introduction, such as how to add intermediate, middleware, such as routing. This article mainly talk about the principle, such as how to build the intermediate processing chain, how to write their own middleware and so on.
Negroni Handler Processor
Essentially Negroni
an HTTP Handler, because he implements the HTTP Handler interface, so he can be http.ListenAndServe
used, followed by a set Negroni
of their own internal Handler processing chain, through which they can achieve the purpose of processing HTTP requests, The processors in these handler processing chains are middleware.
123 |
func(n *negroni)servehttp(rw http. Responsewriter, R *http. Request) {n.middleware.servehttp (Newresponsewriter (rw), R)} |
The above code, is the implementation of the Negroni
HTTP handler, so that the label Library and the HTTP seamless integration. Implemented HTTP Handler, for HTTP request, there is a unified portal, all the HTTP Requet processing, will be Negroni
passed through the method to the ServeHTTP
Negroni
internal registration of the middleware.
12345 |
type Interface {servehttp (rw http. Responsewriter, R *http. Request, next http. Handlerfunc)}typefunc(rw http. Responsewriter, R *http. Request, next http. Handlerfunc) |
This is Negroni
your own definition of the handler processor, which is very similar to the HTTP handler, the only difference is that one more next
parameter, which next
is the core of the middleware processing chain.
How to build a middleware processing chain
We already know that we Negroni
have our own set of handler middleware processing chain, so this processing chain and how to build it? To solve this riddle, let's first look at Negroni
how to register a middleware.
12345678910111213 |
type struct {Middleware Middlewarehandlers []handler}func(n *negroni)use(Handler Handler) {if Nil {panic("Handler cannot be nil"append(n.handlers, handler) N.middleware = Build (N.handlers)} |
When we call the Use
method, we will put Negroni
the Handler in its own handlers
field, this is a slice type field, can save our stored Negroni Handler. The middleware processing chain is built based on the slice that holds the Negroni handler middleware
.
1234 |
type struct {handler Handlernext *middleware} |
middleware
Structs have very simple, there are two fields, one is the current Negroni Handler, and the other is the middleware
pointer down one next
. With such a middleware
struct, you can build a perfect middleware processing chain.
1234567891011121314151617181920 |
func build(handlers []handler) middleware {varNext middlewareif Len(handlers) = =0{returnVoidmiddleware ()}Else if Len(handlers) >1{next = Build (handlers[1:])}Else{next = Voidmiddleware ()}returnmiddleware{handlers[0], &next}} func voidmiddleware() middleware {returnMiddleware{handlerfunc ( func(rw http. Responsewriter, R *http. Request, next http. Handlerfunc) {}), &middleware{},}} |
The above code is to construct a middleware processing chain logic, which is a recursive function, logic is relatively simple.
When the handlers
argument is empty, voidMiddleware
an empty one is returned directly from the function middleware
.
When the handlers
parameter has only 1 processors, the build is milldeware
not next
, so next
it is obtained through the voidMiddleware
function, and then generated by the return middleware{handlers[0], &next}
composition middleware
and returned.
The last situation is that there are more than 1 Negroni Handler, that through the build
function loop recursion, starting from the 2nd Handler, continue to recursive processing, so the first added Negroni Handler will be placed in front of the middleware processing chain, It also means that it will be implemented as a priority.
How middleware is called
How can these middleware be called when the processor chain is built? In the previous chapters, we talked about the Negroni is an HTTP Handler, so the total entrance is in the ServeHTTP
method.
123 |
func(n *negroni)servehttp(rw http. Responsewriter, R *http. Request) {n.middleware.servehttp (Newresponsewriter (rw), R)} |
As can be seen from the above code, the method is called middleware.ServeHTTP
, which is the beginning of the implementation of the middleware.
123 |
func(M middleware)servehttp(rw http. Responsewriter, R *http. Request) {m.handler.servehttp (rw, R, m.next.servehttp)} |
middleware.ServeHTTP
The current handler method in the method invocation middleware
ServeHTTP
executes the middleware processing logic we write ourselves.
12345 |
type func(rw http. Responsewriter, R *http. Request, next http. Handlerfunc)func(H handlerfunc)servehttp(rw http. Responsewriter, R *http. Request, next http. Handlerfunc) {h (RW, R, next)} |
Back here again, Handler's method of ServeHTTP
execution, essentially the execution of our own defined Negroni. Handlerfunc.
The current middleware is executed, so how is the next trigger? This is the next parameter in our own definition of the middleware function. After we have finished processing our middleware, we need to call the next function to continue executing the next middleware if we feel it is necessary, and if we do not call the next function, then the processing of the middleware chain is broken. See an example of a custom middleware.
1234567 |
func (l *logger) servehttp (rw http.) Responsewriter, R *http. Request, next http. Handlerfunc) {start: = time. Now () Next (RW, R)//Omit extraneous code } |
This is the implementation of the Negroni built-in log middleware, and you can see that it calls the next(rw, r)
function, allowing the middleware processing chain to continue executing. next(rw, r)
What is this? Actually, we talked about it earlier.
123 |
func(M middleware)servehttp(rw http. Responsewriter, R *http. Request) {m.handler.servehttp (rw, R, m.next.servehttp)} |
next
Function call, is the next middleware
ServeHTTP
call again, this is a recursive, but also the middleware processing chain design of the ingenious, flexible control, free choice whether to invoke the next middleware.
Go Language Classic library usage analysis, not to be continued, welcome to sweep code attention flysnow_org
to the public number or website http://www.flysnow.org/, the first time to see the following series. If you feel helpful, share it with your friends and thank you for your support.
Conversion between HTTP handler and Negroni handler
When we first introduced Negroni, we know that it is compatible with HTTP handler, Negroni can directly convert the HTTP handler to Negroni HTTP, so that we can use HTTP handler directly as a Negroni middleware, Let's see how it's converted.
1234567 |
func (n *negroni) Usehandler (Handler http. Handler) {n.use (Wrap (Handler)}}func(n *negroni)usehandlerfunc func (rw http.) Responsewriter, R *http. Request) {n.usehandler (http. Handlerfunc (Handlerfunc))} |
Negroni provides two methods, respectively compatible http.Handler
and http.HandlerFunc
, UseHandlerFunc
method is essentially called UseHandler
method, the UseHandler
focus of the method implementation is Wrap(handler)
that it completes the HTTP. Handler to Negroni.handler conversion.
123456 |
func Wrap (Handler http. Handler)Handler {return handlerfunc (func(rw http. Responsewriter, R *http. Request, next http. Handlerfunc) {handler. Servehttp (RW, R) Next (rw, R)})} |
This function is essentially the implementation of the Negroni middleware, and its code logic is to execute the implementation of the http.Handler
middleware first and then invoke the next(rw, r)
next middleware.
Introduction to built-in middleware
Negroni has several middleware built into it, and when we Classic
create one through *Negroni
the function, we have
123 |
func Classic () *Negroni {return New (Newrecovery (), Newlogger (), Newstatic (http. Dir ("public"))} |
NewRecovery
, NewLogger
and NewStatic
is this several built-in middleware, are implemented Negroni handler middleware, the specific source code you can see, here is not specifically introduced.
Write your own middleware
Writing their own middleware, in the Negroni can be used in two ways, one is http.Handler
the way, the advantages of this approach is everyone is familiar with, and has been, the disadvantage is that you can not control the processing chain middleware, the default is to call the next middleware, we can not interrupt.
The other is the way it is implemented negroni.Handler
, and this is the way Negroni recommends it.
123456789101112131415161718192021222324252627282930 |
//blog:www.flysnow.org//wechat:flysnow_org func main() {N: = Negroni. New () N.usefunc (Printauthorinfo) router:=http. Newservemux () router. Handle ("/", Handler ()) N.usehandler (router) n.run (": 1234")} func printauthorinfo(rw http. Responsewriter, R *http. Request, next http. Handlerfunc) {FMT. Println ("Blog:www.flysnow.org") FMT. Println ("wechat:flysnow_org") Next (Rw,r)} func handler() http. Handler {returnhttp. Handlerfunc (MyHandler)} func myhandler(rw http. Responsewriter, R *http. Request) {rw. Header (). Set ("Content-type","Text/plain") Io. WriteString (RW,"Hello World")} |
We printAuthorInfo
implement a Negroni handler middleware through the function, which is very simple, just prints some author information, then executes the next middleware.
When using, we n.UseFunc(printAuthorInfo)
register this middleware, we start the service, access, http://localhost:1234
you can see the following information in the console:
12 |
Blog: www.flysnow.orgWechat:flysnow_org |
For example, I this middleware is relatively simple, we can meet their own needs to achieve their own business middleware.
Some middleware introduction
GitHub has a lot of third-party middleware developed specifically for Negroni to match the use of Negroni, such as gzip, oauth2.0, etc., and you can view the third party's intermediate list by following the links below:
Https://github.com/urfave/negroni#third-party-middleware
Summary
Here, Negroni this middleware analysis is over, there may be some no analysis, such as With
methods, Run
methods, they are relatively simple, we can see.
Another important thing is that NewResponseWriter
this function, which is the wrapper for us now NewResponseWriter
, adds some additional information to this knowledge point I used in this article Go Language Classic Library analysis (iv) | Gorilla Handlers source code Implementation analysis of the article in detail, it will not repeat the introduction.
HTTP middleware, is an HTTP interceptor, Negroni for the interceptor processing better, can be flexible control, whether terminal, etc., reasonable use of Negroni, you can make more effort.
Go Language Classic library usage analysis, not to be continued, welcome to sweep code attention flysnow_org
to the public number or website http://www.flysnow.org/, the first time to see the following series. If you feel helpful, share it with your friends and thank you for your support.