如何将数据从中间件传递给处理程序?

Dip*_*pen 12 go

我正在设计我的处理程序以返回http.Handler.这是我的处理程序的设计:

 func Handler() http.Handler {
  return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  })
}
Run Code Online (Sandbox Code Playgroud)

我的中间件设计为接受http.Handler,然后在中间件完成其操作后调用处理程序.这是我的中间件的设计:

 func Middleware(next http.Handler) http.Handler {
  return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    // Middleware operations

    next.ServeHTTP(w, r)
  })
}
Run Code Online (Sandbox Code Playgroud)

考虑到我的中间件和处理程序的设计,将信息从中间件传递给处理程序的正确方法是什么?我试图从中间件传递给处理程序的信息是从请求正文解析的JSON Web令牌.如果我没有将解析后的JWT传递给处理程序,那么我将需要在我的处理程序中再次解析JWT.在中间件和处理程序中解析JWT的请求主体似乎很浪费.为了防止这些信息相关,我使用带有gorilla mux的标准net/http库.

Jus*_*tin 12

由于您已经在使用Gorilla,请查看上下文包.

(如果您不想更改方法签名,这很好.)

import (
    "github.com/gorilla/context"
)

...

func Middleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        // Middleware operations
        // Parse body/get token.
        context.Set(r, "token", token)

        next.ServeHTTP(w, r)
    })
}

...

func Handler() http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        token := context.Get(r, "token")
    })
}
Run Code Online (Sandbox Code Playgroud)


Von*_*onC 7

第一种方法,类似的问题,是codemodus/chainDaved.

包链有助于处理请求范围数据的Handler包装链的组成.

它使用了与Context处理程序相结合的概念Context:

func ctxHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
    // ...

    if s, ok := getMyString(ctx); ok {
        // s = "Send this down the line."
    }

    // ...
}
Run Code Online (Sandbox Code Playgroud)

另一种方法:您可以查看Matt Silverlock()的 " 自定义处理程序和避免Go Web应用程序中的全局 " .(这里有完整的例子)elithrar

我们的想法是定义ServeHTTP一个包含相关背景的类型.

// We've turned our original appHandler into a struct with two fields:
// - A function type similar to our original handler type (but that now takes an *appContext)
// - An embedded field of type *appContext
type appHandler struct {
    *appContext
    h func(*appContext, http.ResponseWriter, *http.Request) (int, error)
}

// Our ServeHTTP method is mostly the same, and also has the ability to
// access our *appContext's fields (templates, loggers, etc.) as well.
func (ah appHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    // Updated to pass ah.appContext as a parameter to our handler type.
    status, err := ah.h(ah.appContext, w, r)
    if err != nil {
        log.Printf("HTTP %d: %q", status, err)
        switch status {
        case http.StatusNotFound:
            http.NotFound(w, r)
            // And if we wanted a friendlier error page, we can
            // now leverage our context instance - e.g.
            // err := ah.renderTemplate(w, "http_404.tmpl", nil)
        case http.StatusInternalServerError:
            http.Error(w, http.StatusText(status), status)
        default:
            http.Error(w, http.StatusText(status), status)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

appContext结构中,您可以放置​​要传递的任何数据.


Ken*_*ant 6

现在,传递请求范围的数据的正确方法是在标准库中使用上下文包。

https://golang.org/pkg/context/

您可以通过http.Request上的request.Context访问它。