在Go中简单实现HTTP服务中间件
通常一个简单http服务框架,就是注册一堆路由,然后根据路由调用不同的逻辑去处理。
但实际上可能有一些统一的处理对几乎所有的路由都涉及到,比如日志,比如权限等等。
那么这个时候搞一个中间做预处理,是一个不错的想法。
定义一个中间件单元:
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 }
然后将路由处理函数用中间件入口包裹起来:
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 }
最后注册你需要的中间件即可:
mwa = MakeMiddleWareAdaptor() // init middleware mwa.Regist("/", testMWAfunc, testMWAfunc2) // regist middleware ... func testMWAfunc(w http.ResponseWriter, r *http.Request) (bool, error) { log.Println("我是第一个中间件...") 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("我是第二个中间件...") return false, nil // return false,break follow-up actions. }
代码虽然简单,记录一个思路。