Golang HTTP自定义错误处理响应



我正在经历https://blog.golang.org/error-handling-and-go最后,它给出了一个很好的例子,说明如何以更干净的方式处理返回的错误,并做了一些简单的事情:

// Wrapper for handler functions.
type rootHandler func(http.ResponseWriter, *http.Request) error
// Implement the http.Handler interface.
func (fn rootHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
err := fn(w, r) // Call handler function.
if err == nil {
return
}
...
}
// POST /api/test/
testRouter.
Handle("/", rootHandler(create)).
Methods("POST")
// GET /api/test/{id}/
testRouter.
HandleFunc("/{id:[0-9]+}/", rootHandler(getByID)).
Methods("GET")
func create(w http.ResponseWriter, r *http.Request) error {
// CustomError implementes error
return &CustomError{
Kind:       EPARSE,
Status:     http.StatusBadRequest,
Message:    "some message",
Op:         "create",
Err:        err,
}
}

这运行得很好,但我不希望将每个控制器方法(在本例中为create(都封装在rootHandler中,并认为最好的方法是找到某种后中间件。我试图创建一个后中间位置,路由器使用它来代替每个控制器方法,但我失败了,我想知道如何实现它。关于SO,我能找到的最接近的答案是emmbee关于如何将Go中间件模式与错误返回请求处理程序相结合的答案?除了AuthMiddleware中的fn将是控制器方法之外。

因此,理想情况下,如果存在,我会有下面的处理程序来处理CustomError

// POST /api/test
testRouter.
Handle("/", create).
Methods("POST")

就上下文而言,我使用大猩猩mux和negroni。

欢迎提出任何想法!非常感谢。

理想的解决方案将无法运行。mux API支持http.Handlerfunc(http.ResponseWriter, *http.Request)参数。你有一个func(http.ResponseWriter, *http.Request) errorfunc(http.ResponseWriter, *http.Request) error不能作为mux API支持的参数类型之一传递。

唯一的解决方案是使用rootHandler包装器使每个控制器函数适应mux API所支持的类型。与标准http.HandlerFunc包装器相比,该包装器不增加开销。

使用辅助函数来减少包装器所需的代码量:

func handle(r *mux.Router, p string, fn func(http.ResponseWriter, *http.Request) error) *mux.Route {
return r.Handle(path, rootHandler(fn))
}
...
handle(testRouter, "/", create).Methods("POST")
handle(testRouter, "/{id:[0-9]+}/", getByID).Methods("GET")

使用助手功能中的类型开关来处理不同的控制器类型:

func handle(r *mux.Router, p string, h interface{}) *mux.Route {
switch h := h.(type) {
case func(http.ResponseWriter, *http.Request) error:
return r.Handle(p, rootHandler(h))
case func(http.ResponseWriter, *http.Request):
return r.HandleFunc(p, h)
case http.Handler:
return r.Handle(p, h)
default:
panic(fmt.Sprintf("handler type %T not supported", h))
}
}

最新更新