Ale*_*lex 6 middleware go go-alice
我熟悉Go中间件模式,如下所示:
// Pattern for writing HTTP middleware.
func middlewareHandler(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Our middleware logic goes here before executing application handler.
next.ServeHTTP(w, r)
// Our middleware logic goes here after executing application handler.
})
}
Run Code Online (Sandbox Code Playgroud)
例如,如果我有一个loggingHandler:
func loggingHandler(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Before executing the handler.
start := time.Now()
log.Printf("Strated %s %s", r.Method, r.URL.Path)
next.ServeHTTP(w, r)
// After executing the handler.
log.Printf("Completed %s in %v", r.URL.Path, time.Since(start))
})
}
Run Code Online (Sandbox Code Playgroud)
还有一个简单的handleFunc:
func handleFunc(w http.ResponseWriter, r *http.Request) {
w.Write([]byte(`Hello World!`))
}
Run Code Online (Sandbox Code Playgroud)
我可以这样组合它们:
http.Handle("/", loggingHandler(http.HandlerFunc(handleFunc)))
log.Fatal(http.ListenAndServe(":8080", nil))
Run Code Online (Sandbox Code Playgroud)
这一切都很好.
但我喜欢Handlers能够像普通函数一样返回错误的想法.这使得错误处理变得更加容易,因为如果出现错误我只能返回错误,或者只是在函数结束时返回nil.
我这样做了:
type errorHandler func(http.ResponseWriter, *http.Request) error
func (f errorHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
err := f(w, r)
if err != nil {
// log.Println(err)
fmt.Println(err)
os.Exit(1)
}
}
func errorHandle(w http.ResponseWriter, r *http.Request) error {
w.Write([]byte(`Hello World from errorHandle!`))
return nil
}
Run Code Online (Sandbox Code Playgroud)
然后像这样包装它来使用它:
http.Handle("/", errorHandler(errorHandle))
Run Code Online (Sandbox Code Playgroud)
我可以将这两种模式分开工作,但我不知道如何将它们组合起来.我喜欢我能够用Alice这样的库链接中间件.但如果他们也可以返回错误那就太好了.我有办法实现这个目标吗?
我也喜欢这种 HandlerFuncs 返回错误的模式,它更简洁,你只需编写一次错误处理程序。只需将您的中间件与其包含的处理程序分开考虑,您不需要中间件来传递错误。中间件就像一个链,依次执行每个中间件,然后最后一个中间件知道您的处理程序签名,并适当地处理错误。
因此,以最简单的形式,保持您拥有的中间件完全相同,但最后插入具有这种形式的中间件(并且不执行另一个中间件,而是一个特殊的 HandlerFunc):
// Use this special type for your handler funcs
type MyHandlerFunc func(w http.ResponseWriter, r *http.Request) error
// Pattern for endpoint on middleware chain, not takes a diff signature.
func errorHandler(h MyHandlerFunc) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Execute the final handler, and deal with errors
err := h(w, r)
if err != nil {
// Deal with error here, show user error template, log etc
}
})
}
Run Code Online (Sandbox Code Playgroud)
...
然后像这样包装你的函数:
moreMiddleware(myMiddleWare(errorHandler(myhandleFuncReturningError)))
Run Code Online (Sandbox Code Playgroud)
这意味着这个特殊的错误中间件只能包装您的特殊函数签名,并位于链的末尾,但这很好。此外,我会考虑将此行为包装在您自己的多路复用器中,以使其更简单一些并避免传递错误处理程序,并让您更轻松地构建中间件链,而无需在路由设置中进行丑陋的包装。
我认为如果您使用的是路由器库,则可能需要明确支持此模式才能工作。您可以在此路由器中以修改后的形式看到此示例,它完全使用您所追求的签名,但处理构建中间件链并在没有手动包装的情况下执行它:
https://github.com/fragmenta/mux/blob/master/mux.go
| 归档时间: |
|
| 查看次数: |
2333 次 |
| 最近记录: |