3

问题: 无法从中间件访问 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:49PM EST):所以在删除中间件(或至少注释掉试图读取 mux.CurrentRoute 的部分)之后,我能够从目标 handlerfunc 检索路由名称(例如: usersCreateHandlerFunc 或brandCreateHandlerFunc)。这并不能解决我的问题(我仍然想在中间件中执行身份验证/授权,而不是每个 handlerfunc),我有一种预感,它让我知道 *mux.Router 在我的中间件中不可用,直到最终之后.ServeHTTP 调用。(或类似的规定...)

更新(2015-01-04 @ 5:41PM EST):尝试了使用 Negroni 作为中间件组件的不同(尽管不太受欢迎)方向。当我尝试获取 mux.CurrentRoute 时仍然出现零指针错误。

更新(2015-01-04 @ 6:17PM EST):我能够从中间件 func 访问请求(例如:r.URL),但仍然无法访问 mux.Route(例如:mux.CurrentRoute( r))。在多看多路复用源之后,我认为这是因为当前的多路复用上下文没有设置,因为路由器还没有执行匹配器(因此它不知道它当前在哪个路由上,直到中间件之后已经完成)。但是,我仍然不确定如何解决这个问题,或者重新构建我的代码来处理这个问题。

4

3 回答 3

2

CurrentRoute godoc

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

在您的示例中,您的链mwAuthenticate, mwAuthorize连接到路由“/”而不使用 gorilla mux。这意味着当请求通过您的处理程序时,它还没有通过 gorilla mux 路由器。

尝试以下操作(您的示例已精简):

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
}
于 2017-05-15T06:56:57.317 回答
2

关于什么:

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

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

于 2020-07-22T01:39:31.407 回答
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

于 2015-02-13T22:16:44.097 回答