嵌套的Gorilla Mux路由器无法工作。

huangapple go评论94阅读模式
英文:

Nested Gorilla Mux router does not work

问题

使用下面的代码,当我访问/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()
// 在这里添加管理员路由

// 为管理员中间件创建一个新的Negroni
router.Handle("/admin", negroni.New(
  Middleware1, 
  Middleware2, 
  negroni.Wrap(adminRoutes),
)) 

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

我熟悉Mux中的Subrouter的概念,但据我所知,我不能以类似上面示例的方式使用它,特别是我不能在mainRouter和其Subrouter之间插入任何内容。这就是为什么嵌套看起来更灵活的原因。

英文:

Using code below, when I access /test2 it responds with 404 - not found. /test1 works correctly. Why is that? Is nesting not allowed despite the fact that routers implement http.Handler interface?

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

EDIT:

My main goal was to add some initial work which would be common for all routes in subRouter, and only for them. To be even more specific, I would like to use Negroni as my middleware orchiestrator.
On the Negroni website there is an example of adding middleware to the group of routes:

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 basically executes ServeHTTP methods of every argument, since all of them implement http.Handler. It executes them in order, so router routes will be last.

I'm familiar with the concept of Subrouter in Mux, but AFAIK I can't use it in similar fashion as example above, in particular, I can't inject anything between mainRouter and its Subrouter. This is why nesting looks more flexible.

答案1

得分: 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")
    })

    // 在mux中,你需要使用与处理程序匹配的相同路径注册子路由器
    mainRouter.Handle("/test2", subRouter)

    // 如果你的子路由器有与其他子路径匹配的处理程序,你也需要这样做
    mainRouter.Handle("/test2/{_dummy:.*}", subRouter)

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

希望这对某人有所帮助。

英文:

I know this question is somewhat old, but I have spent some time figuring out how handlers and matching work in go. You can see my experiment code here.

Basically, you can get the effect you want with code like this:

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

I hope this helps someone.

答案2

得分: 8

之前给出的答案都没有帮助到我,无法完全实现我想要做的事情。我试图在许多路由的Subrouter周围使用negroni.Wrap()。我相信这就是原始帖子的作者想要的。

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

package hello

import (
	"fmt"
	"net/http"

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

func init() {
	// 创建“根”路由器
	r := mux.NewRouter().StrictSlash(true)

	// 创建专用于/api的“子路由器”,它将使用PathPrefix
	apiRouter := mux.NewRouter().PathPrefix("/api").Subrouter().StrictSlash(true)

	// 这一步是将我们的“根”路由器和“子路由器”连接在一起的地方。
	r.PathPrefix("/api").Handler(negroni.New(
		negroni.HandlerFunc(myMiddleware),
		negroni.Wrap(apiRouter),
	))

	// 使用r定义“根”路由
	r.HandleFunc(genHandleFunc("/", "站点根目录"))
	r.HandleFunc(genHandleFunc("/home", "主页"))

	// 使用apiRouter定义“子路由器”路由,前缀为/api
	apiRouter.HandleFunc(genHandleFunc("/", "API根目录,/api"))                                       // 匹配:/api
	apiRouter.HandleFunc(genHandleFunc("/v1", "API V1根目录,/api/v1"))                               // 匹配:/api/v1
	apiRouter.HandleFunc(genHandleFunc("/v1/resourceabc", "API V1 - resourceabc,/api/v1/resourceabc")) // 匹配:/api/v1/resourceabc

	/* 最后,我们将我们的“根”路由器传递给net/http库。根路由器将包含所有/api的路由。
	*/
	http.Handle("/", r)
}

// 快速生成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, "在执行工作之前...")
	next(w, r)
	fmt.Fprintln(w, "在执行工作之后...")
}
英文:

None of the previous answers given helped me achieve exactly what I was seeking out to do. I was trying to use negroni.Wrap() around a Subrouter with lots of routes. I believe that is what the original poster wanted.

Additional Context: I am deploying on Google App Engine, hence putting everything in the init() function.

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

得分: 6

在这种情况下,你不需要使用两个路由器。

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

英文:

You wouldn't use two routers here anyway.

Gorilla Mux has the concept of a Subrouter, whereby you define the top level domain properties on the main router, then use the Subrouter instance to map the individual paths.

For example:

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)

You can go even further than that though - for example, you may have another router at /test1 and a subrouter that matches anything further below that (say /test1/othertest).

答案4

得分: 4

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

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

Use full path in subroutes:

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

huangapple
  • 本文由 发表于 2014年8月4日 02:26:25
  • 转载请务必保留本文链接:https://go.coder-hub.com/25107763.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定