我希望从处理程序中提取一些重复的逻辑,并将其放入每个处理程序的中间件中:特别是诸如CSRF检查,检查现有会话值(即用于auth或预览页面)之类的东西。
我已经阅读了一些有关此的文章,但是许多示例着重于每个服务器的中间件(包装http.Handler):我有一小部分需要中间件的处理程序。我的其他大部分页面都没有,因此,如果可以避免检查会话等。对于那些要求更好。
http.Handler
到目前为止,我的中间件通常看起来像这样:
func checkCSRF(h http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { // get the session, check/validate/create the token based on HTTP method, etc. // return HTTP 403 on a failed check // else invoke the wrapped handler h(w, r) } }
但是,在许多情况下,我想将一个变量传递给包装的处理程序:生成的CSRF令牌传递给模板,或者包含表单数据的结构- 一块中间件在会话之前检查会话是否存在某些保存的表单数据用户点击一个/preview/URL,否则它将重定向他们(因为他们没有预览内容!)。
/preview/
我想将该结构传递给包装的处理程序,以节省重复会话的需要。我刚刚在中间件中编写的获取/类型声明/错误检查逻辑。
我可以这样写:
type CSRFHandlerFunc func(w http.ResponseWriter, r *http.Request, t string)
…然后像这样编写中间件:
func csrfCheck(h CSRFHandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { // get the session, check/validate/create the/a token based on HTTP method, etc. // return HTTP 403 on a failed check // else invoke the wrapped handler and pass the token h(w, r, token) }
…但是提出了一些问题:
r.HandleFunc("/path/preview/", checkCSRF(checkExisting(previewHandler)))
在可能的情况下,我会尽量避免陷入“写库不要被困”的陷阱,但是中间件是我很可能在项目生命后期添加/构建的东西,我希望“第一次”。
一些指导对此将不胜感激。到目前为止,Go 在编写Web应用程序方面一直 很棒 ,但是在它的现阶段尚无大量示例,因此我有点儿依赖。
如果我正确理解了您的问题,那么您正在寻找一种将其他参数传递给中间件的便捷方法,对吗?
现在,定义这些参数是很重要的。它们可能是您的中间件的一些配置值- 可以在构造Handler类型时进行设置。代替NewMyMiddleware(MyHandler),您做NewMyMiddleware(MyHandler, "parameter"),这里没问题。
NewMyMiddleware(MyHandler)
NewMyMiddleware(MyHandler, "parameter")
但是在您的情况下,您似乎想要传递每个请求参数,例如CSRF令牌。将这些参数传递给处理函数将修改其签名,并且会偏离标准Handler[Func]接口。在这种情况下,中间件之间的紧密耦合是正确的。
Handler[Func]
您曾提到过自己的解决方案– 我认为上下文地图 是 解决此问题的可行工具。这不是 说 很难一个写自己- 你基本上需要map[*http.Request]interface{}和RWMutex安全的并发访问。尽管如此,仅仅使用gorilla/context就足够了–看起来(相对)成熟,编写良好的包,带有不错的API。
map[*http.Request]interface{}
RWMutex
gorilla/context
无耻的插件:如果您要处理CSRF检查,为什么不试试我的nosurf软件包呢?