<p>guys i am working on coding a router called <a href="https://github.com/emostaf/garson">Garson</a> , and i am trying to implement methods on my router that makes it easy to hook middlewares</p>
<p>i have 2 methods for that, one is called Before() and the other is called After() , the idea is, Before() calles middlewares before each request, and After() executes middlewares after each request.</p>
<p>in my ServeHTTP method, i am trying to execute each handler, my problem is when i execute the handler of the requested route, i am not able to execute the handler of the next middleware - which would be the first middleware of the middlewares registered with After()-, i have tried to call handler.ServeHTTP() and then next.ServeHTTP() but this only executes the first middleware registered with After() and ignores the others.</p>
<p>here is my <a href="https://github.com/emostafa/garson/blob/middleware/router.go#L149">ServeHTTP() method</a></p>
<p>here is example of usage, where middleware package is from github.com/emostafa/garson/middleware</p>
<pre><code>func main() {
router := garson.New()
router.Before(middleware.Logger)
router.After(someCustomMiddlewareOfYours)
router.Get("/hello", hello)
http.ListenAndServe(":3000", router)
}
</code></pre>
<hr/>**评论:**<br/><br/>R2A2: <pre><p>Why not this?</p>
<pre><code>func main() {
router := garson.New()
router.Get("/hello", anotherCustomMiddleware(hello))
http.ListenAndServe(":3000", someCustomMiddleware(middleware.Logger(router)))
}
</code></pre>
<p>In this way a middleware can act on individual routes, or the whole router. No need to have before/after - just wrap at whichever level.</p>
<p>BTW I think you're totally on the right track with plain http.Handlers and with <code>func(http.Handler) http.Handler</code> - this makes your work more flexible than other routers & middlewares (negroni/httprouter/etc etc), which use their own custom parameter specs. Not a criticism of their authors - they were working in a pre-<code>r.Context()</code> world, which forced their hands a little. Good for you.</p>
<p>Edit: sorry I forgot to include an example which does middleware-type stuff before/after running the inner handler/router/middleware.</p>
<p>See below:</p>
<p><a href="https://github.com/laher/context-example/blob/master/main.go#L124" rel="nofollow">https://github.com/laher/context-example/blob/master/main.go#L124</a></p>
<p>That repo is just some code samples I made for a meetup talk. See readme for more notes.</p>
<p>Does that answer your question?</p></pre>emostafa: <pre><p>@R2A2 my idea was that, you might need to execute some code after each response, for example, if you want to store some logs, how would you do that using:</p>
<pre><code> router.Get("/hello", anotherCustomMiddleware(hello))
</code></pre>
<p>another thing that i have in mind, is if i have like 3 or 4 middlewares that i want to execute before the request, that would be something like this ?</p>
<pre><code>router.Get("/hello", middleware1(middleware2(middleware3(hello))))
</code></pre>
<p>my idea that it could look like this</p>
<pre><code>router.Get("/hello", hello).Before(middleware1, middleware2, middleware3).After(middleware4)
</code></pre>
<p>of Use() of the whole concept of Before() and After() is wrong:
router.Use(LoggerMiddleware)
router.Get("/hello", hello).Use(middleware1, middleware2, middleware3, middleware4)</p>
<p>glad you liked the idea of going with plain http.Handler, this way my router could be flexible and to be used with any other libraries. I am glad that i am did something good :D thanks for your motiviation.</p></pre>R2A2: <pre><p>Here's a logging example (not storing but hopefully it illustrates the idea):</p>
<pre><code>func anotherCustomMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
log.Println("start", time.Now(), r.Method, "-", r.RequestURI)
next.ServeHTTP(w, r)
log.Println("finish", time.Now(), r.Method, "-", r.RequestURI, w.Status)
})
}
</code></pre>
<p>Sorry I don't really value the Before/After/Use thing that much. I think you'd typically have most middlewares wrapped around a single router, and then maybe zero/one/2 middlewares around the individual routes, so not very troublesome. If you're getting more complex than that I'd recommend nesting routers instead. I think Use() just adds an unnecessary layer. But, up to you.</p></pre>
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889
- 请尽量让自己的回复能够对别人有帮助
- 支持 Markdown 格式, **粗体**、~~删除线~~、
`单行代码`
- 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
- 图片支持拖拽、截图粘贴等方式上传