【问题标题】:Nested Gorilla Mux router does not work嵌套的 Gorilla Mux 路由器不起作用
【发布时间】:2014-09-26 06:46:39
【问题描述】:

使用下面的代码,当我访问 /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。它按顺序执行它们,因此路由器路由将在最后。

我熟悉 Mux 中 Subrouter 的概念,但我无法以与上面示例类似的方式使用它,特别是,我无法在 mainRouter 和它的 Subrouter 之间注入任何东西。这就是嵌套看起来更灵活的原因。

【问题讨论】:

    标签: go mux gorilla


    【解决方案1】:

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

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

    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)
    }
    

    我希望这对某人有所帮助。

    【讨论】:

    • 所以即使你用mainRouter 调用了http.ListenAndServe,subRouter 也会被包括在内?
    【解决方案2】:

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

    附加上下文:我在 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...")
    }
    

    【讨论】:

      【解决方案3】:

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

      Gorilla Mux 具有 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)。

      【讨论】:

      • 我已经编辑了我的问题,以便更具体地说明我想要实现的目标。我认为 Subrouter 解决不了这个问题。
      • 如果您演示示例的另一半会很好:/test1/othertest
      【解决方案4】:

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

      router := mux.NewRouter()
      
      apiRoutes := mux.NewRouter()
      apiRoutes.Handle("/api/auth", Auth)
      
      router.PathPrefix("/api").Handler(negroni.New(
        Middleware1,
        Middleware2,
        negroni.Wrap(apiRoutes),
      )) 
      

      【讨论】:

        猜你喜欢
        • 2021-06-05
        • 2015-06-17
        • 2014-09-08
        • 2016-04-07
        • 2017-11-07
        • 1970-01-01
        • 1970-01-01
        • 2015-04-05
        • 2014-12-16
        相关资源
        最近更新 更多