如何将数据从中间件传递到处理程序?
Posted
技术标签:
【中文标题】如何将数据从中间件传递到处理程序?【英文标题】:How can I pass data from middleware to handlers? 【发布时间】:2015-07-19 18:22:52 【问题描述】:我正在设计我的处理程序以返回 http.Handler。这是我的处理程序的设计:
func Handler() http.Handler
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request)
)
我的中间件设计为接受 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)
)
考虑到我的中间件和处理程序的设计,将信息从中间件传递到处理程序的正确方法是什么?我试图从中间件传递给处理程序的信息是从请求正文解析的 JSON Web 令牌。如果我没有将解析的 JWT 传递给处理程序,那么我将需要在我的处理程序中再次解析 JWT。在中间件和处理程序中解析 JWT 的请求正文似乎很浪费。以防万一这些信息是相关的,我将标准的 net/http 库与 gorilla mux 一起使用。
【问题讨论】:
【参考方案1】:既然您已经在使用Gorilla,请查看context 包。
(如果您不想更改方法签名,这很好。)
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")
)
更新
Gorilla context
包现在处于维护模式根据 repo:
注意 gorilla/context 在 context.Context 存在之前就已经诞生了,它不能很好地与 http.Request.WithContext(添加到 net/http Go 1.7 及更高版本)执行的请求的浅拷贝。
在这些情况下使用 gorilla/context 可能会导致内存泄漏,因为指向每个 http.Request 的指针都变得“孤立”并且在发送响应时不会被清理。
您应该使用 Go 1.7 中的 http.Request.Context() 功能。
【讨论】:
与直接使用内置 golang 上下文相比有什么好处? @KarelBílek Poster 提到使用 Gorilla 工具包,它有自己的上下文包,早于 Go (与许多其他库一样)。它现在处于维护模式,他们建议使用 Go 的 context 包。更新了这个答案以反映,谢谢。 啊,我错过了约会。好的【参考方案2】:现在传递请求范围数据的正确方法是标准库中的上下文包。
https://golang.org/pkg/context/
您可以通过 http.Request 上的 request.Context 访问它。
【讨论】:
是的,这很好用。您可以在此处找到更多示例和说明:gocodecloud.com/blog/2016/11/15/…【参考方案3】:类似于问题的第一种方法是codemodus/chain
by Daved。
包链有助于构成承载请求范围数据的处理程序包装链。
它使用notion of Context
,加上一个上下文处理程序:
func ctxHandler(ctx context.Context, w http.ResponseWriter, r *http.Request)
// ...
if s, ok := getMyString(ctx); ok
// s = "Send this down the line."
// ...
另一种方法:您可以查看Matt Silverlock (elithrar
) 的“Custom Handlers and Avoiding Globals in Go Web Applications”。 (full example here)
这个想法是在包含相关上下文的类型上定义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)
在appContext
结构中,您可以放置您想要传递的任何数据。
【讨论】:
以上是关于如何将数据从中间件传递到处理程序?的主要内容,如果未能解决你的问题,请参考以下文章
如何将数据从顶点着色器传递到片段着色器,中间有着色器[重复]
如何将数据从 express 中间件直接传递回客户端 JWT 和 Express 中间件