如何使用 gorilla mux 为所有路由应用相同的处理程序
How to apply the same handler for all routes with gorilla mmux
我正在使用一个有价值的 rootHandler
来处理生成的错误。我想知道如何将此处理程序用于我的 api 可能服务的每个端点。
r := mux.NewRouter()
r.Handle("/api/endpoint0", rootHandler(function0)).Methods("POST")
r.HandleFunc("/api/endpoint1", function1).Methods("POST")
r.HandleFunc("/api/endpoint2", function2).Methods("POST")
s := &http.Server{
Handler: r,
Addr: "127.0.0.1:8080",
WriteTimeout: 15 * time.Second,
ReadTimeout: 15 * time.Second,
}
我的错误处理程序工作如下:
type rootHandler func(http.ResponseWriter, *http.Request) error
func (fn rootHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
err := fn(w, r) // Call handler function
if err == nil {
return
}
//log error or w/e
}
func NewHTTPError(err error, status int, detail string) error {
return &HTTPError{
Cause: err,
Detail: detail,
Status: status,
}
}
我使用的示例函数之一:
func function0(w http.ResponseWriter, r *http.Request) (err error) {
if err = notLogged(); err != nil {
return NewHTTPError(err, 400, "not authorized")
}
}
我是否必须用 rootHanlder(functionName) 包装每个路由函数,或者有没有办法将它应用于每个路由?
根据您 rootHandler
的确切结构,您或许可以将其设置为中间件:
func GetRootHandlerMW(authUser SomeType) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Do what needs to be done?
next.ServeHTTP(w, r)
})
}
}
...
r.Use(GetRootHandlerMW(authUser))
一个简单的日志记录中间件如下所示:
func LogMW(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
logRequest(...)
next.ServeHTTP(w, r)
})
}
...
r.Use(LogMW)
从您添加的代码来看,您似乎想将 HTTP 处理函数更改为 return 错误。这会更改函数的签名,您不能将其用作处理程序。您可以:
- 使用上下文将错误传回中间件。也就是说,在处理程序的请求上下文中设置一些错误值,以便记录器中间件可以在处理程序 returns 或
之后记录它
- 用错误记录器包装每个处理程序,就像您现在所做的那样。
向上下文添加值会创建一个新的上下文,因此如果您使用上下文从处理程序传回值,则必须先设置一个占位符。像这样:
type RequestError struct {
Err error
}
type requestErrorKeyType int
const requestErrorKey requestErrorKeyType=iota
func SetRequestError(req *http.Request, err error) {
if r:=req.Context().Value(requestErrorKey); r!=nil {
r.(*RequestError).Err=err
}
}
// In the handler...
requestError:=RequestError{}
newReq:=request.WithContext(request.Context().WithValue(requestErrorKey,&requestError))
next.ServeHTTP(w,newReq)
if requestError.Err!=nil {
...
}
我正在使用一个有价值的 rootHandler
来处理生成的错误。我想知道如何将此处理程序用于我的 api 可能服务的每个端点。
r := mux.NewRouter()
r.Handle("/api/endpoint0", rootHandler(function0)).Methods("POST")
r.HandleFunc("/api/endpoint1", function1).Methods("POST")
r.HandleFunc("/api/endpoint2", function2).Methods("POST")
s := &http.Server{
Handler: r,
Addr: "127.0.0.1:8080",
WriteTimeout: 15 * time.Second,
ReadTimeout: 15 * time.Second,
}
我的错误处理程序工作如下:
type rootHandler func(http.ResponseWriter, *http.Request) error
func (fn rootHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
err := fn(w, r) // Call handler function
if err == nil {
return
}
//log error or w/e
}
func NewHTTPError(err error, status int, detail string) error {
return &HTTPError{
Cause: err,
Detail: detail,
Status: status,
}
}
我使用的示例函数之一:
func function0(w http.ResponseWriter, r *http.Request) (err error) {
if err = notLogged(); err != nil {
return NewHTTPError(err, 400, "not authorized")
}
}
我是否必须用 rootHanlder(functionName) 包装每个路由函数,或者有没有办法将它应用于每个路由?
根据您 rootHandler
的确切结构,您或许可以将其设置为中间件:
func GetRootHandlerMW(authUser SomeType) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Do what needs to be done?
next.ServeHTTP(w, r)
})
}
}
...
r.Use(GetRootHandlerMW(authUser))
一个简单的日志记录中间件如下所示:
func LogMW(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
logRequest(...)
next.ServeHTTP(w, r)
})
}
...
r.Use(LogMW)
从您添加的代码来看,您似乎想将 HTTP 处理函数更改为 return 错误。这会更改函数的签名,您不能将其用作处理程序。您可以:
- 使用上下文将错误传回中间件。也就是说,在处理程序的请求上下文中设置一些错误值,以便记录器中间件可以在处理程序 returns 或 之后记录它
- 用错误记录器包装每个处理程序,就像您现在所做的那样。
向上下文添加值会创建一个新的上下文,因此如果您使用上下文从处理程序传回值,则必须先设置一个占位符。像这样:
type RequestError struct {
Err error
}
type requestErrorKeyType int
const requestErrorKey requestErrorKeyType=iota
func SetRequestError(req *http.Request, err error) {
if r:=req.Context().Value(requestErrorKey); r!=nil {
r.(*RequestError).Err=err
}
}
// In the handler...
requestError:=RequestError{}
newReq:=request.WithContext(request.Context().WithValue(requestErrorKey,&requestError))
next.ServeHTTP(w,newReq)
if requestError.Err!=nil {
...
}