我已经使用适配器模式创建了中进器。我的中间软件之一是用于身份验证。因此,如果未授权用户,则我必须向用户发送回复,并且不应调用下一个中间软件。
// 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)
,因此,对于其他条件,我们还需要打破Adapt
功能的for
循环,否则即使在发送响应后也会调用Next Middleware。<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
让我知道是否还有其他方法可以处理这种情况。
链中的下一个中间件仅在您明确调用时运行。
下一个中间件以h
传递给您的关闭,您正在调用h.ServeHTTP()
来调用它。如果您不打电话,则没有其他中间件运行,因此您必须提供完整的HTTP响应。
适应功能与服务请求无关。它甚至在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返回而无需致电下一个中间件,则可以发送您喜欢的任何响应;就像您在任何其他处理程序中一样。
顺便说一句,您想要让迭代以相反的顺序适应。我不确定您是否知道首先通知执行,然后同时参与,然后checkauth,然后再添加。
中间件通常被束缚。有一些框架可以为您做。一个光滑的例子是爱丽丝。
chain := alice.New(th.Throttle, timeoutHandler, nosurf.NewPure).Then(myHandler)
如果您想自己做,则可以使用递归来避免循环。例如(来自此链接(:
// 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)]...))
}
每个中间件接收下一个作为参数。因此,下一个必须由上一个处理程序手动调用,否则链停止。因此,在您的身份中间软件中,如果auth失败,则不必拨打下一个,而链条停止,而错误状态是返回的最后一件事。因此,在您的代码中,您需要接受http.Handler
的参数,这是下一个处理程序(中间件功能必须具有func(http.Handler) http.Handler
的签名(。有关更多详细信息,请参见此博客。
您可能还需要设置正确的HTTP状态代码。包括这样的东西:
http.Error(w, "Forbidden: xyz", http.StatusForbidden)