首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >从Golang的中间件发回响应的最佳方式是什么?

从Golang的中间件发回响应的最佳方式是什么?
EN

Stack Overflow用户
提问于 2018-02-21 14:16:47
回答 3查看 1.2K关注 0票数 3

我已经使用Adapter模式创建了中间件。我的一个中间件是用于身份验证的。因此,如果用户未被授权,那么我必须向用户返回响应,并且不应该调用下一个中间件。

代码语言:javascript
运行
复制
// 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循环,否则它将调用下一个中间件,即使在发送响应之后。

如果有任何其他方法来处理这种情况,请告诉我。

EN

回答 3

Stack Overflow用户

发布于 2018-02-21 16:10:01

链中的下一个中间件只有在您显式调用它时才会运行。

下一个中间件作为h传递给您的闭包,您可以通过调用h.ServeHTTP()来调用它。如果不调用此方法,则不会运行其他中间件,因此必须提供完整的HTTP响应。

票数 3
EN

Stack Overflow用户

发布于 2018-02-21 16:59:33

适配器功能与服务请求无关。它在HTTP服务器启动之前执行一次(并且只执行一次)。请注意,它返回一个http.Handler,但它本身不是一个http.Handler。

在这种情况下,适配器返回的处理程序的行为如下:

代码语言:javascript
运行
复制
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。

票数 2
EN

Stack Overflow用户

发布于 2018-02-21 14:29:36

中间件通常是链式的。有一些框架可以帮你做到这一点。Alice就是一个很好的例子。

代码语言:javascript
运行
复制
chain := alice.New(th.Throttle, timeoutHandler, nosurf.NewPure).Then(myHandler)

如果你想自己做这件事,你可以使用递归来避免for循环。例如(来自此link):

代码语言:javascript
运行
复制
// 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状态代码。包括如下内容:

代码语言:javascript
运行
复制
http.Error(w, "Forbidden: xyz", http.StatusForbidden)
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/48899277

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档