我已经使用Adapter模式创建了中间件。我的一个中间件是用于身份验证的。因此,如果用户未被授权,那么我必须向用户返回响应,并且不应该调用下一个中间件。
// Adapter type
type Adapter func(http.Handler) http.Handler
// Adapt func
func Adapt(h http.Handler, adapters ...Adapter) http.Handler {
// Call all middleware
for _, adapter := range adapters {
h = adapter(h)
}
return h
}
// CheckAuth middleware
func CheckAuth() Adapter {
return func(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Get Authorization token from the header
// Validate the token
// if valid token then call h.ServeHTTP(w, r)
// else send response 401 to the user,
if(validUser){
h.ServeHTTP(w, r)
}else{
fmt.Fprintf(w, "Unauthorized")
}
return h
}
}
}
http.Handle("/", Adapt(indexHandler, AddHeader(),
CheckAuth(),
CopyMgoSession(db),
Notify(logger),
)在CheckAuth中间件中,只有当用户被授权时,我才会调用h.ServeHTTP(w, r),因此对于else条件,我们还需要中断Adapt函数的for循环,否则它将调用下一个中间件,即使在发送响应之后。
如果有任何其他方法来处理这种情况,请告诉我。
发布于 2018-02-21 16:10:01
链中的下一个中间件只有在您显式调用它时才会运行。
下一个中间件作为h传递给您的闭包,您可以通过调用h.ServeHTTP()来调用它。如果不调用此方法,则不会运行其他中间件,因此必须提供完整的HTTP响应。
发布于 2018-02-21 16:59:33
适配器功能与服务请求无关。它在HTTP服务器启动之前执行一次(并且只执行一次)。请注意,它返回一个http.Handler,但它本身不是一个http.Handler。
在这种情况下,适配器返回的处理程序的行为如下:
var indexHandler http.Handler
func handlerWithMiddleWare(w http.ResponseWriter, r *http.Request) {
notify := func(w http.ResponseWriter, r *http.Request) {
copyMgoSession := func(w http.ResponseWriter, r *http.Request) {
checkAuth := func(w http.ResponseWriter, r *http.Request) {
addHeader := func(w http.ResponseWriter, r *http.Request) {
indexHandler.ServeHTTP(w, r)
}
addHeader(w, r)
}
checkAuth(w, r)
}
copyMgoSession(w, r)
}
notify(w, r)
}因此,如果您让CheckAuth返回,而不调用下一个中间件,则可以发送您喜欢的任何响应;就像在任何其他处理程序中一样。
顺便说一句,你想让Adapt以相反的顺序迭代。我不确定您是否知道Notify首先执行,然后是CopyMgoSession,然后是CheckAuth,最后是AddHeader。
发布于 2018-02-21 14:29:36
中间件通常是链式的。有一些框架可以帮你做到这一点。Alice就是一个很好的例子。
chain := alice.New(th.Throttle, timeoutHandler, nosurf.NewPure).Then(myHandler)如果你想自己做这件事,你可以使用递归来避免for循环。例如(来自此link):
// buildChain builds the middlware chain recursively, functions are first class
func buildChain(f http.HandlerFunc, m ...middleware) http.HandlerFunc {
// if our chain is done, use the original handlerfunc
if len(m) == 0 {
return f
}
// otherwise nest the handlerfuncs
return m[0](buildChain(f, m[1:cap(m)]...))
}每个中间件接收下一个as参数。因此,下一个处理程序必须由前一个处理程序手动调用,否则链将停止。因此,在您的身份验证中间件中,如果身份验证失败并且链停止,错误状态是最后返回的内容,则不必调用下一个中间件。因此,在您的代码中,您需要接受http.Handler参数,这就是下一个处理程序(中间件函数必须具有func(http.Handler) http.Handler的签名)。有关更多详细信息,请参阅此blog。
您可能还想设置正确的http状态代码。包括如下内容:
http.Error(w, "Forbidden: xyz", http.StatusForbidden)https://stackoverflow.com/questions/48899277
复制相似问题