示例:
package main
import (
"fmt"
"net/http"
"github.com/urfave/negroni"
)
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
fmt.Fprintf(w, "Welcome to the home page!")
})
n := negroni.Classic() // Includes some default middlewares
n.UseHandler(mux)
http.ListenAndServe(":3000", n)
}以negroni实例包裹mux(路由)实例,再传递给net/http作为http.Handler处理函数即可实现中间件功能!
how to run negroni:
1) 直接下载到$GOPATH/src
go run server.go
2) 借助go mod,可以管控版本
go mod init xxx // xxx为自定义的此module的name
go mod tidy
go run server.go
negroni.Classic()
negroni.Classic()handler
- negroni.Handler interface:
type Handler interface {
ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc)
}- http.Handler interface:
type Handler interface {
ServeHTTP(w ResponseWriter, r *Request)
}对比negroni.Handler和http.Handler,符合negroni.Handler接口的实例对象增加一个回调功能,可以调用下一级的http.HandlerFunc.为什么是http.HandlerFunc,而非negroni.HandlerFunc?可能是negroni在调用时,在next中再调用下一级negroni.HandlerFunc(未看源码,仅为猜测)
如何书写middleware func,然后将之添加到链路:
func MyMiddleware(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
// do some stuff before
next(rw, r)
// do some stuff after
}
n := negroni.New()
n.Use(negroni.HandlerFunc(MyMiddleware))或者直接传入http.Handler函数,添加到链路:
n := negroni.New()
mux := http.NewServeMux()
// map your routes
n.UseHandler(mux)?此处http.Handler无next回调功能,是否就在此处直接开始回溯
测试如下:
func healthHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "I'm alive!")
}
func indexHandler(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello World!\n"))
fmt.Fprintln(w, "hello world!")
}
n.UseHandler(http.HandlerFunc(indexHandler))
n.UseHandler(http.HandlerFunc(healthHandler))结果显示,未回溯:
Hello World!
hello world!
I'm alive!functions
With()
WithWithHandlerNegroni// middleware we want to reuse
common := negroni.New()
common.Use(MyMiddleware1)
common.Use(MyMiddleware2)
// `specific` is a new negroni with the handlers from `common` combined with the
// the handlers passed in
specific := common.With(
SpecificMiddleware1,
SpecificMiddleware2
)Run()
Runn.Run(":8080")Route Specific Middleware
If you have a route group of routes that need specific middleware to be executed, you can simply create a new Negroni instance and use it as your route handler.
这是一个很重要的功能,大多数实际应用场景下,都需要只对某个子路由实现具体的中间件.
其实思路很简单,原本将negroni实例应用到ListenAndServe()中,作为根Handler;现在将negroni实例应用到路由处理函数即可.
Gorilla Mux应用为例:
router := mux.NewRouter()
subRouter := mux.NewRouter().PathPrefix("/subpath").Subrouter().StrictSlash(true)
subRouter.HandleFunc("/", someSubpathHandler) // "/subpath/"
subRouter.HandleFunc("/:id", someSubpathHandler) // "/subpath/:id"
// "/subpath" is necessary to ensure the subRouter and main router linkup
router.PathPrefix("/subpath").Handler(negroni.New(
Middleware1,
Middleware2,
negroni.Wrap(subRouter),
))With()router := mux.NewRouter()
apiRoutes := mux.NewRouter()
// add api routes here
webRoutes := mux.NewRouter()
// add web routes here
// create common middleware to be shared across routes
common := negroni.New(
Middleware1,
Middleware2,
)
// create a new negroni for the api middleware
// using the common middleware as a base
router.PathPrefix("/api").Handler(common.With(
APIMiddleware1,
negroni.Wrap(apiRoutes),
))
// create a new negroni for the web middleware
// using the common middleware as a base
router.PathPrefix("/web").Handler(common.With(
WebMiddleware1,
negroni.Wrap(webRoutes),
))Bundled Middleware
详见参考