中间件
中间件就是在请求/响应周期中插入代码。中间件的常见用例是日志记录(Buffalo已经做过),身份验证请求等。
“已知”中间件包列表可以在toolkit.gobuffalo.io/tools?topic=m...找到。
中间件接口
中间件接口收入是buffalo.Handler,输出也是buffalo.Handler。
func MyMiddleware(next buffalo.Handler) buffalo.Handler {
return func(c buffalo.Context) error {
// do some work before calling the next handler
err := next(c)
// do some work after calling the next handler
return err
}
}
通过实现buffalo.MiddlewareFunc接口,我们可以实现控制整个应用的执行流程。
使用中间件
a := buffalo.New(buffalo.Options{})
a.Use(MyMiddleware)
a.Use(AnotherPieceOfMiddleware)
在上面的示例中,所有请求将首先通过MyMiddleware中间件,然后AnotherPieceOfMiddleware中间件,再进入最终处理程序。
注意:应用程序中定义的中间件由该应用程序中的所有路由和组自动继承。
在action中使用中间件
有时候,我们只想在一个操作上使用一个中间件,而不是在整个应用或者资源上。
因为一个中间件的定义就是接受buffalo.Handler
并返回一个buffalo.Handler
, 所以你可以包装任何buffalo.Handler
。
a := buffalo.New(buffalo.Options{})
a.GET("/foo", MyMiddleware(MyHandler))
当然,中间件也可以包含中间件。
a := buffalo.New(buffalo.Options{})
a.GET("/foo", MyMiddleware(AnotherPieceOfMiddleware(MyHandler)))
组中间件
a := buffalo.New(buffalo.Options{})
a.Use(MyMiddleware)
a.Use(AnotherPieceOfMiddleware)
g := a.Group("/api")
// authorize the API end-point
g.Use(AuthorizeAPIMiddleware)
g.GET("/users", UsersHandler)
a.GET("/foo", FooHandler)
在上面的例子中MyMiddleware
,AnotherPieceOfMiddleware
将在所有请求上有效,但AuthorizeAPIMiddleware
只在/api/*
路由上有效。
GET /foo -> MyMiddleware -> AnotherPieceOfMiddleware -> FooHandler
GET /api/users -> MyMiddleware -> AnotherPieceOfMiddleware -> AuthorizeAPIMiddleware -> UsersHandler
跳过中间件
有时候,我们希望将中间件添加到整个应用程序或组中,但是个别几个单独的处理程序除外。
// actions/app.go
a := buffalo.New(buffalo.Options{})
a.Use(AuthorizeUser)
// skip the AuthorizeUser middleware for the NewUser and CreateUser handlers.
a.Middleware.Skip(AuthorizeUser, NewUser, CreateUser)
a.GET("/users/new", NewUser)
a.POST("/users", CreateUser)
a.GET("/users", ListUsers)
a.GET("/users/{id}", ShowUser)
有效的中间件如下:
GET /users/new -> NewUser
POST /users -> CreateUser
GET /users -> AuthorizeUser -> ListUsers
GET /users/{id} -> AuthorizeUser -> ShowUser
重要信息:要跳过的中间件功能和操作功能必须是同一个Go实例。
// EXAMPLE 2
app.Resource("/widgets", WidgetResource{})
app.Skip(mw, WidgetResource{}.Show) // WON'T WORK
wr := WidgetResource{}
app.Resource("/widgets", wr)
app.Skip(mw, wr.Show) // WORKS
因为两次WidgetResource{},是两个不同的实例。
跳过资源操作
有时候我们需要对某个资源设定中间件,但是需要跳过某些action。例如,允许guest用户查看List和Show操作上的资源,但在行动的其余要求授权。
没有加中间件之前是这样的。
app.Resource("/widgets", WidgetResource{})
加上中间件如下:
res := WidgetResource{}
wr := app.Resource("/widgets", res)
wr.Middleware.Skip(Authorize, res.Index, res.Show)
清除中间件
由于中间件是从其父级继承的,因此有时可能需要从“空白”中间件集开始
代码如下:
// actions/app.go
a := buffalo.New(buffalo.Options{})
a.Use(MyMiddleware)
a.Use(AnotherPieceOfMiddleware)
g := a.Group("/api")
// clear out any previously defined middleware
g.Middleware.Clear()
g.Use(AuthorizeAPIMiddleware)
g.GET("/users", UsersHandler)
a.GET("/foo", FooHandler)
对应的路由中间件为:
GET /foo -> MyMiddleware -> AnotherPieceOfMiddleware -> FooHandler
GET /api/users -> AuthorizeAPIMiddleware -> UsersHandler
列出应用的中间件
要获得应用程序正在使用的中间件的完整列表(通过分组细分),可以通过运行buffalo task middleware
命令找到。
$ buffalo t middleware
-> /
github.com/gobuffalo/buffalo.*App.defaultErrorMiddleware
github.com/gobuffalo/buffalo.*App.PanicHandler
github.com/gobuffalo/buffalo.RequestLoggerFunc
github.com/gobuffalo/buffalo.sessionSaver
github.com/gobuffalo/mw-forcessl.Middleware.func1
github.com/markbates/coke/actions.App.func1
github.com/markbates/coke/actions.trackLastURL
github.com/markbates/coke/actions.TrackingCookie
github.com/markbates/coke/actions.App.func3
github.com/gobuffalo/mw-paramlogger.ParameterLogger
github.com/gobuffalo/mw-csrf.glob..func1
github.com/gobuffalo/buffalo-pop/pop/popmw.Transaction.func2
github.com/markbates/coke/actions.SetCurrentUser
github.com/markbates/coke/actions.SetPageTitle
-> /courses/{course_slug}
github.com/gobuffalo/buffalo.*App.defaultErrorMiddleware
github.com/gobuffalo/buffalo.*App.PanicHandler
github.com/gobuffalo/buffalo.RequestLoggerFunc
github.com/gobuffalo/buffalo.sessionSaver
github.com/gobuffalo/mw-forcessl.Middleware.func1
github.com/markbates/coke/actions.App.func1
github.com/markbates/coke/actions.trackLastURL
github.com/markbates/coke/actions.TrackingCookie
github.com/markbates/coke/actions.App.func3
github.com/gobuffalo/mw-paramlogger.ParameterLogger
github.com/gobuffalo/mw-csrf.glob..func1
github.com/gobuffalo/buffalo-pop/pop/popmw.Transaction.func2
github.com/markbates/coke/actions.SetCurrentUser
github.com/markbates/coke/actions.SetPageTitle
github.com/markbates/coke/actions.FindCourse
-> /admin
github.com/gobuffalo/buffalo.*App.defaultErrorMiddleware
github.com/gobuffalo/buffalo.*App.PanicHandler
github.com/gobuffalo/buffalo.RequestLoggerFunc
github.com/gobuffalo/buffalo.sessionSaver
github.com/gobuffalo/mw-forcessl.Middleware.func1
github.com/markbates/coke/actions.App.func1
github.com/markbates/coke/actions.trackLastURL
github.com/markbates/coke/actions.TrackingCookie
github.com/markbates/coke/actions.App.func3
github.com/gobuffalo/mw-paramlogger.ParameterLogger
github.com/gobuffalo/mw-csrf.glob..func1
github.com/gobuffalo/buffalo-pop/pop/popmw.Transaction.func2
github.com/markbates/coke/actions.SetCurrentUser
github.com/markbates/coke/actions.SetPageTitle
github.com/markbates/coke/actions.Authorize
github.com/markbates/coke/actions.AuthorizeAdmin