从中间件获取gorilla / mux路由器当前路由名称

时间:2015-01-04 18:06:39

标签: http go middleware gorilla

问题: 无法从中间件访问mux.CurrentRoute(r).GetName()。 (虽然我能够从我的中间件访问它,但我必须改变我的中间件的工作方式,因为它以前无法访问请求)。所以我已经搞砸了一些事情,我不知道如何回到可以访问路线名称的工作状态。

非常感谢任何帮助!

错误:

runtime error: invalid memory address or nil pointer dereference 

代码:

func main() {
    var (
        err          error
        r            *mux.Router
        devRouter    *mux.Router
        usersRouter  *mux.Router
        brandsRouter *mux.Router
    )
    defer db.Close()
    defer store.Close()

    r = mux.NewRouter()
    devRouter = r.PathPrefix("/api/v1/dev").Subrouter()
    usersRouter = r.PathPrefix("/api/v1/users").Subrouter()
    brandsRouter = r.PathPrefix("/api/v1/brands").Subrouter()

    // development endpoints
    devRouter.HandleFunc("/db/seed", devDbSeed)
    ...

    // users
    usersRouter.HandleFunc("/create", usersCreateHandlerFunc).Methods("POST").Name("USERS_CREATE")
    ...

    // brands
    brandsRouter.HandleFunc("/create", brandsCreateHandlerFunc).Methods("POST").Name("BRANDS_CREATE")
    ...

    // products
    brandsRouter.HandleFunc("/{brand_id:[0-9]+}/products", brandsProductsListHandlerFunc).Methods("GET").Name("BRANDS_PRODUCTS_LIST")
    ...

    // mwAuthorize and mwAuthenticate basically work the same
    mw := []func(http.Handler) http.Handler{mwAuthenticate, mwAuthorize}
    http.Handle("/", use(r, mw...))
    err = http.ListenAndServe(":9000", nil)
    if err != nil {
         logIt(err)
    }
}

func use(h http.Handler, mw ...func(http.Handler) http.Handler) http.Handler {
    // exec order: mw[0],mw[1],mw[N]...
    for i := len(mw) - 1; i >= 0; i-- {
        h = mw[i](h)
    }
    return h
}

func mwAuthorize(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
         if true != authorize(r) {
            w.WriteHeader(http.StatusForbidden)
            return
         } else {
            next.ServeHTTP(w, r)
         }
     })
}

func authorize(r *http.Request) (isAuthorized bool) {
    isAuthorized = false
    /**
       This is where it's failing!
    */
    routeName := mux.CurrentRoute(r).GetName()
    switch routeName {
    case "USERS_CREATE":
        // route-specific authorization
        break
    ...
    default:
        break
    }
    return
}

更新(2015-01-04 @美国东部时间下午4:49): 因此,在删除中间件(或者至少注释掉试图读取mux.CurrentRoute的部分)之后,我能够从目标handlerfunc中检索路由名称(例如:usersCreateHandlerFunc或brandsCreateHandlerFunc)。这并没有解决我的问题(我仍然希望在中间件中执行身份验证/授权而不是每个handlerfunc),我有一种预感让我知道* mux.Router isn&#39 ;在我的中间件中可用,直到最后的.ServeHTTP调用。 (或者沿着这些方向......)

更新(2015-01-04 @美国东部时间下午5:41): 尝试使用Negroni作为中间件组件的不同(尽管不太优选)方向。当我尝试获取mux.CurrentRoute时,仍然会收到nil-pointer错误。

更新(2015-01-04 @美国东部时间下午6:17): 我能够从中间件函数访问请求(例如:r.URL),但仍然没有运气访问mux.Route(例如:mux.CurrentRoute(r))。在了解多路复用源之后,我认为这是因为当前的多路复用上下文没有设置,因为路由器还没有执行匹配器(因此它没有知道它在中间件完成之后的当前路径是什么。但是,我仍然不确定如何解决此问题,或重新构建我的代码来处理此问题。

3 个答案:

答案 0 :(得分:1)

来自CurrentRoute godoc

  

CurrentRoute返回当前请求的匹配路由(如果有)。这仅在匹配路由的处理程序内部调用时才有效,因为匹配的路由存储在请求上下文[...]

在您的示例中,您的package main import ( "fmt" "log" "net/http" "github.com/gorilla/mux" ) var ( err error r *mux.Router devRouter *mux.Router ) func devDbSeed(w http.ResponseWriter, r *http.Request) { fmt.Fprintln(w, "devDbSeed") return } func main() { r = mux.NewRouter() devRouter = r.PathPrefix("/api/v1/dev").Subrouter() // mwAuthorize and mwAuthenticate basically work the same mw := []func(http.Handler) http.Handler{mwAuthenticate, mwAuthorize} // development endpoints devRouter.Handle("/db/seed", use(http.HandlerFunc(devDbSeed), mw...)).Name("foo") // Send all requests into the mux router err = http.ListenAndServe(":9000", r) if err != nil { log.Fatal(err) } } func use(h http.Handler, mw ...func(http.Handler) http.Handler) http.Handler { // exec order: mw[0],mw[1],mw[N]... for i := len(mw) - 1; i >= 0; i-- { h = mw[i](h) } return h } func mwAuthorize(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if !authorize(r) { w.WriteHeader(http.StatusForbidden) return } next.ServeHTTP(w, r) }) } func mwAuthenticate(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { next.ServeHTTP(w, r) }) } func authorize(r *http.Request) (isAuthorized bool) { isAuthorized = false handlerName := "UNKNOWN" if route := mux.CurrentRoute(r); route != nil { routeName := route.GetName() if routeName != "" { handlerName = routeName } } log.Println(handlerName) switch handlerName { case "USERS_CREATE": // route-specific authorization log.Println("USERS_CREATE") break default: break } return } 链附加到路径“/”而不使用gorilla mux。这意味着当请求通过处理程序时,它还没有通过gorilla mux路由器。

尝试以下操作(您的示例已被删除):

sqlSave(sqlOdbc, insertRows, tablename = "Products", 
append = TRUE, verbose = TRUE, 
colnames = c("Code","DefaultSupplierSku","Name","Size","DefaultSupplierID","BrandID","ProductTypeID","BuyPrice","SellPrice")
)

答案 1 :(得分:1)

那:

routeName := mux.CurrentRoute(r).GetName()

r*http.Request的地方。不要忘记导入"github.com/gorilla/mux"。请记住,要使用此名称,必须在定义时给您一个路由名称

答案 2 :(得分:0)

我有同样的问题,我以这种方式解决了:

var match mux.RouteMatch
routeExists := s.Router.Match(r, &match)
if routeExists && match.Route.GetName(){
    routeName := match.Route.GetName()
}

当我定义路线时,我添加了.Name("route/:param"),其中route/:param是我的路线。