从Golang的中间软件中寄回响应的最佳方法是什么?



我已经使用适配器模式创建了中进器。我的中间软件之一是用于身份验证。因此,如果未授权用户,则我必须向用户发送回复,并且不应调用下一个中间软件。

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

最新更新