10

使用下面的代码,当我访问 /test2 它以 404 响应 - 未找到。/test1 工作正常。这是为什么?尽管路由器实现了 http.Handler 接口,但不允许嵌套吗?

package main

import (
    "fmt"
    "net/http"
    "github.com/gorilla/mux"
)

func main() {

    mainRouter := mux.NewRouter()
    subRouter := mux.NewRouter()

    mainRouter.HandleFunc("/test1", func(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, "test1") })

    subRouter.HandleFunc("/test2", func(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, "test2") })

    mainRouter.Handle("/", subRouter)

    http.ListenAndServe(":9999", mainRouter)
}

编辑:

我的主要目标是添加一些初始工作,这些工作对于 subRouter 中的所有路由都是通用的,并且仅适用于它们。更具体地说,我想使用Negroni作为我的中间件编排器。在 Negroni 网站上有一个将中间件添加到路由组的示例:

router := mux.NewRouter()
adminRoutes := mux.NewRouter()
// add admin routes here

Create a new negroni for the admin middleware
router.Handle("/admin", negroni.New(
  Middleware1, 
  Middleware2, 
  negroni.Wrap(adminRoutes),
)) 

Negroni 基本上执行每个参数的 ServeHTTP 方法,因为它们都实现了 http.Handler。它按顺序执行它们,因此路由器路由将在最后。

我熟悉SubrouterMux 中的概念,但是我不能以与上面示例类似的方式使用它,特别是,我不能在 mainRouter 和它的Subrouter. 这就是嵌套看起来更灵活的原因。

4

4 回答 4

12

我知道这个问题有点老了,但我花了一些时间来弄清楚处理程序和匹配如何在 go 中工作。你可以在这里看到我的实验代码。

基本上,你可以用这样的代码得到你想要的效果:

package main

import (
    "fmt"
    "net/http"
    "github.com/gorilla/mux"
)

func main() {

    mainRouter := mux.NewRouter()
    subRouter := mux.NewRouter()

    mainRouter.HandleFunc("/test1", func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprint(w, "test1")
    })
    subRouter.HandleFunc("/test2", func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprint(w, "test2")
    })

    // in mux, you need to register subrouter
    // with the same path that the handlers in
    // it are matching
    mainRouter.Handle("/test2", subRouter)

    // if your subrouter has handlers that match
    // other sub paths - you also need to do this
    mainRouter.Handle("/test2/{_dummy:.*}", subRouter)

    http.ListenAndServe(":9999", mainRouter)
}

我希望这可以帮助别人。

于 2014-12-05T22:07:12.967 回答
8

之前给出的答案都没有帮助我实现我想要做的事情。我试图negroni.Wrap()在 a 周围Subrouter使用很多路线。我相信这就是原始海报想要的。

附加上下文:我在 Google App Engine 上进行部署,因此将所有内容都放在init()函数中。

package hello

import (
    "fmt"
    "net/http"

    "github.com/codegangsta/negroni"
    "github.com/gorilla/mux"
)

func init() {
    // Create the "root" router, if you will...
    r := mux.NewRouter().StrictSlash(true)

    // Create your "Subrouter" dedicated to /api which will use the PathPrefix
    apiRouter := mux.NewRouter().PathPrefix("/api").Subrouter().StrictSlash(true)

    // This step is where we connect our "root" router and our "Subrouter" together.
    r.PathPrefix("/api").Handler(negroni.New(
        negroni.HandlerFunc(myMiddleware),
        negroni.Wrap(apiRouter),
    ))

    // Define "root" routes using r
    r.HandleFunc(genHandleFunc("/", "root of site"))
    r.HandleFunc(genHandleFunc("/home", "home"))

    // Define "Subrouter" routes using apiRouter, prefix is /api
    apiRouter.HandleFunc(genHandleFunc("/", "root of API, /api"))                                       // Matches: /api
    apiRouter.HandleFunc(genHandleFunc("/v1", "root of API V1, /api/v1"))                               // Matches: /api/v1
    apiRouter.HandleFunc(genHandleFunc("/v1/resourceabc", "API V1 - resourceabc, /api/v1/resourceabc")) // Matches: /api/v1/resourceabc

    /* Finally we pass our "root" router to the net/http library. The "root" router will contain all
    of the routes for /api also.
    */
    http.Handle("/", r)
}

// Silly function to quickly generate a HandleFunc
func genHandleFunc(p string, msg string) (path string, f func(http.ResponseWriter, *http.Request)) {
    path = p
    f = func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "%v\n", msg)
    }
    return
}

func myMiddleware(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
    fmt.Fprintln(w, "Before doing work...")
    next(w, r)
    fmt.Fprintln(w, "After doing work...")
}
于 2015-05-29T19:53:04.110 回答
6

无论如何,您不会在这里使用两个路由器。

Gorilla Mux 具有 a 的概念Subrouter,您可以在主路由器上定义顶级域属性,然后使用Subrouter实例映射各个路径。

例如:

mainRouter := mux.NewRouter()
subRouter := mainRouter.PathPrefix("/").Subrouter()

subRouter.HandleFunc("/test1", func(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, "test1") })
subRouter.HandleFunc("/test2", func(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, "test2") })

mainRouter.Handle("/", mainRouter)

不过,您可以走得更远——例如,您可能有另一个路由器/test1和一个子路由器,它与低于该位置的任何东西相匹配(比如/test1/othertest)。

于 2014-08-03T23:00:16.610 回答
4

在子路由中使用完整路径:

router := mux.NewRouter()

apiRoutes := mux.NewRouter()
apiRoutes.Handle("/api/auth", Auth)

router.PathPrefix("/api").Handler(negroni.New(
  Middleware1,
  Middleware2,
  negroni.Wrap(apiRoutes),
)) 
于 2015-03-01T15:07:05.767 回答