Simple Implementation of HTTP Service Middleware in Go

Usually a simple http service framework is to register a bunch of routes and then call different logic to process them according to the routing.

But in fact, there may be some uniform processing involved in almost all routes, such as logging, such as permissions and so on.

So it's a good idea to do a pretreatment in the middle at this time.

Define a middleware unit:

 1 package main
 2 
 3 import (
 4     "net/http"
 5 )
 6 
 7 // AdaptorHandle middleware func type
 8 type AdaptorHandle func(w http.ResponseWriter, r *http.Request) (next bool, err error)
 9 
10 // MiddleWareAdaptor router middlewares mapped by url
11 type MiddleWareAdaptor struct {
12     URLs map[string][]AdaptorHandle
13 }
14 
15 // MakeMiddleWareAdaptor make a middleware adaptor
16 func MakeMiddleWareAdaptor() *MiddleWareAdaptor {
17     mwa := &MiddleWareAdaptor{
18         URLs: make(map[string][]AdaptorHandle),
19     }
20 
21     return mwa
22 }
23 
24 // Regist regist a adaptor
25 func (mw *MiddleWareAdaptor) Regist(url string, Adaptor ...AdaptorHandle) {
26     for _, adp := range Adaptor {
27         mw.URLs[url] = append(mw.URLs[url], adp)
28         // mw.URLs[url] = adp
29     }
30 }
31 
32 // Exec exec middleware adaptor funcs...
33 func (mw *MiddleWareAdaptor) Exec(url string, w http.ResponseWriter, r *http.Request) (bool, error) {
34     if adps, ok := mw.URLs[url]; ok {
35         for _, adp := range adps {
36             if next, err := adp(w, r); !next || (err != nil) {
37                 return next, err
38             }
39         }
40     }
41     return true, nil
42 }

Then the routing function is wrapped up with middleware entries:

 1 func middlewareHandler(next http.Handler) http.Handler {
 2     return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 3         // before call handler
 4         start := time.Now()
 5         do, _ := mwa.Exec(r.URL.Path, w, r) // exec middleware
 6         // call next handler
 7         if do {
 8             log.Println("middleware done. next...")
 9             next.ServeHTTP(w, r)
10         } else {
11             log.Println("middleware done.break...")
12         }
13         // after call handle
14         log.Printf("Comleted %s in %v", r.URL.Path, time.Since(start))
15     })
16 }
17 
18 mux.Handle("/", middlewareHandler(&uPlusRouterHandler{}))
19 
20 type uPlusRouterHandler struct {
21 }
22 
23 func (rh *uPlusRouterHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
24 ...
25 }
 

Finally, register the middleware you need:

mwa = MakeMiddleWareAdaptor() // init middleware
mwa.Regist("/", testMWAfunc, testMWAfunc2) // regist middleware
...
func testMWAfunc(w http.ResponseWriter, r *http.Request) (bool, error) {
    log.Println("I am the first Middleware...")
    log.Printf("Started %s %s", r.Method, r.URL.Path)
    return true, nil
}

func testMWAfunc2(w http.ResponseWriter, r *http.Request) (bool, error) {
    log.Println("I am the second Middleware...")
    return false, nil // return false,break follow-up actions.
}

Although the code is simple, record a thought.

Keywords: Go

Added by jsbrown on Sun, 06 Oct 2019 19:18:03 +0300