Go 扩展HTTP处理程序
我的Go web应用程序中有一个相当快速且脏的错误处理程序,它会引发HTTP错误,记录响应的重要部分,并提供一个错误模板。我想消除在处理程序中多次重复编写类似内容的情况:Go 扩展HTTP处理程序,go,Go,我的Go web应用程序中有一个相当快速且脏的错误处理程序,它会引发HTTP错误,记录响应的重要部分,并提供一个错误模板。我想消除在处理程序中多次重复编写类似内容的情况: err := doSomething() if err != nil { serverError(w, r, err, code) } 我已经很好地阅读了这篇文章,其中包括定义一个自定义HTTP处理程序类型,该类型返回如下错误类型/结构(甚至返回int,err): 但我不确定如何保留现有的中间件功能/包装器,它允许我
err := doSomething()
if err != nil {
serverError(w, r, err, code)
}
我已经很好地阅读了这篇文章,其中包括定义一个自定义HTTP处理程序类型,该类型返回如下错误类型/结构(甚至返回int,err):
但我不确定如何保留现有的中间件功能/包装器,它允许我像这样链接中间件:r.handlefun(“/route”,使用(myHandler,middleware1,middleware2))
其中使用
,我的中间件如下所示:
func use(h http.HandlerFunc, middleware ...func(http.HandlerFunc) http.HandlerFunc) http.HandlerFunc {
for _, m := range middleware {
h = m(h)
}
return h
}
func AntiCSRF(h http.HandlerFunc) http.HandlerFunc {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// do something
// h.ServeHTTP(w,r)
}
}
从我所能想到的,它应该是像下面这样的东西(这不起作用)。我收到一个错误,说不能在assignment:needtypeassertion
中使用m(h)(type http.Handler)作为类型appHandler。如何在保持中间件本身“原样”的同时解决此问题
您可以在此处找到一个(简化的)游乐场示例:
我遗漏了什么?还有更好的方法吗?多亏了上的“cronos”的帮助,我成功地解决了这个问题 该解决方案允许我使用自定义处理程序类型,即链中间件,并避免重复必须包装处理程序(即appHandler(myHandler)),中间件…: 对于如下所示的路由:
r.Handle(“/route”,使用(myHandler,someMiddleware))
显然,您可以修改appHandler
以返回您喜欢的任何内容,向appError
添加其他字段,以此类推。如果您想将路由器应用于所有路由,您的中间件也可以包装路由器,即http.Handle(“/”,someMiddleware(r))
func use(h http.HandlerFunc, middleware ...func(http.HandlerFunc) http.HandlerFunc) http.HandlerFunc {
for _, m := range middleware {
h = m(h)
}
return h
}
func AntiCSRF(h http.HandlerFunc) http.HandlerFunc {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// do something
// h.ServeHTTP(w,r)
}
}
r.Handle("/route", use(myHandler, middleware.NoCache)) // Contrived example!
func use(h myHandlerType?, middleware ...func(http.Handler) http.Handler) http.Handler {
for _, m := range middleware {
h = m(h)
}
return h
}
func myHandler(w http.ResponseWriter, r *http.Request) *appError {
// Extremely contrived example
name := "Matt"
_, err := fmt.Fprintf(w, "Hi %s", name)
if err != nil {
return &appError{500, err}
}
return nil
}
func contrivedMiddleware(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Cache-Control", "max-age=0, private, must-revalidate")
w.Header().Set("X-Accel-Expires", "0")
h.ServeHTTP(w, r)
})
}
type appHandler func(http.ResponseWriter, *http.Request) *appError
type appError struct {
Code int
Error error
}
func (fn appHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if e := fn(w, r); e != nil {
switch e.Code {
case http.StatusNotFound:
notFound(w, r)
case http.StatusInternalServerError:
serverError(w, r, e.Error, e.Code)
default:
serverError(w, r, e.Error, e.Code)
}
}
}
func use(h appHandler, middleware ...func(http.Handler) http.Handler) http.Handler {
var res http.Handler = h
for _, m := range middleware {
res = m(res)
}
return res
}
func someMiddleware(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Cache-Control", "max-age=0, private, must-revalidate")
w.Header().Set("X-Accel-Expires", "0")
h.ServeHTTP(w, r)
})
}
func myHandler(w http.ResponseWriter, r *http.Request) *appError {
err := doSomething()
if err != nil {
return &appError{500, err}
}
// render your template, etc.
return nil
}