2017-09-19 49 views
0

我正在構建一個Go Web應用程序,它在處理路由時支持各種中間件功能。我試圖儘可能地堅持net/http,並想知道如何在不使用中間件庫(如negroni)的情況下完成此操作。嵌套函數從切片

本質上,我想要做的是能夠提供一箇中間件功能片,例如一個用於日誌記錄,一個用於檢查有效的JWT,然後是處理請求的處理程序。

我能夠通過定義下面的結構與內格羅尼做到這一點相當簡單:

// Route .. 
type Route struct { 
    Method  string 
    Path  string 
    Middleware []negroni.Handler 
    Handler http.HandlerFunc 
} 

然後定義喜歡的路線:

var commonRoutes = []Route{ 
    { 
     Method:  "GET", 
     Path:  "/info", 
     Middleware: []negroni.Handler{negroni.HandlerFunc(middleware.CheckCache), negroni.HandlerFunc(middleware.Authenticated), negroni.NewLogger()}, 
     Handler: handlers.APIInfo, 
    }, 
} 

最後,當我啓動我的服務器,我引入路由列表,像這樣註冊它們:

for _, r := range routes { 

    handler := append(r.Middleware, negroni.Wrap(r.Handler)) 

    router.Handle(r.Path, negroni.New(handler...)).Methods(r.Method) 
} 

這完美的作品。

任何想法,我如何能夠只用標準net/http簽名和定義中間件處理的方式,像這樣做:

http.Handle("/", middlewareOne(middlewareTwo(finalHandler))) 

謝謝:)

回答

1
func Auth(n http.Handler) http.Handler { 
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 
     log.Printf("Start") 
     n.ServeHTTP(w, r) 
     log.Printf("End") 
    }) 
} 

func processReq(w http.ResponseWriter, r *http.Request) { 
    w.Write([]byte("Success")) 
} 


func main() { 
    handler := http.HandlerFunc(processReq) 

    http.Handle("/",Auth(handler)) 
    http.ListenAndServe(":8000", nil) 
} 

能可以使用http.handler

0

很簡單。您可以定義每個處理程序,像這樣:

// So I don't have to type it over and over... 
type HTTPHandler func(w http.ResponseWriter, r *http.Request) 

func Handler1(next HTTPHandler) HTTPHandler { 
    return func(w http.ResponseWriter, r *http.Request){ 
     // Do stuff 

     if next != nil { 
      next(w, r) 
     } 
    } 
} 

// Handler2 ... HandlerN defined in the same basic way. 

// Chaining: 
http.Handle("/", Handler1(Handler2(nil))) 

每個處理程序將在下次處理程序,並返回一個封閉,做任何你想要加調用下一個處理程序。如果你需要很多這些,可以寫一個類似於這個的幫手:

func MakeHandler(worker, next HTTPHandler) HTTPHandler { 
    return func(w http.ResponseWriter, r *http.Request){ 
     // Maybe have to worker return an error and do standard error 
     // handling here? Could simplify your code some depending on 
     // what you are doing. 
     worker(w, r) 

     if next != nil { 
      next(w, r) 
     } 
    } 
}