示例:

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()

Run
n.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

详见参考

参考: