英文:
Sharing a gorilla/mux router across packages
问题
我在使用gorilla/mux实现轻量级MVC设计时遇到了一些问题。
模块的布局如下:
main.go
-- controllers
---- base.controller.go
---- example.controller.go
-- models
---- base.model.go
---- example.controller.go
controllers
文件夹中的所有文件都属于controllers
包,models
文件夹中的文件也是如此,而main.go
属于main
包。
目前,我只是尝试让Base Controller
能够与main
包共享,这一点已经实现了,但在尝试实现路由时出现了一些错误。编译没有报错,但路由不可用。如果我在Gorilla/Mux文档中实现Walk
函数以打印出所有已注册的路由,则会出现以下错误:
> &{%!!(MISSING)s(*mux.Router=&{<nil> <nil> [0xc4200901b0] map[] true
> false false false}) %!!(MISSING)s(http.HandlerFunc=0xc8df0)
> [%!!(MISSING)s(*mux.routeRegexp=&{/ false false true false
> 0xc420095360 / [] []})] %!!(MISSING)s(*mux.routeRegexpGroup=&{<nil>
> 0xc420016240 []}) %!!(MISSING)s(bool=true) %!!(MISSING)s(bool=false)
> %!!(MISSING)s(bool=false) %!!(MISSING)s(bool=false) <nil>
> %!!(MISSING)s(mux.BuildVarsFunc=<nil>)}
全局变量var V1Router *mux.Router
的原因是首先在main
包中访问它,其次是在其他控制器中创建子路由。
我对Go
还比较新手,但我正在尽力学习最佳实践!非常感谢您的帮助!
以下是示例代码:
base.controllers.go
package controllers
import (
"fmt"
"bytes"
"net/http"
"github.com/gorilla/mux"
)
var V1Router *mux.Router
func init () {
V1Router = mux.NewRouter()
V1Router.StrictSlash(true)
V1Router.HandleFunc("/", BaseHandler)
}
// Base route to access the API Documentation.
func BaseHandler (w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "Hello, Gophers!")
}
main.go
package main
import (
"net/http"
"log"
"github.com/projectrepo/project/models"
"github.com/projectrepo/project/controllers"
"github.com/gorilla/mux"
)
func main () {
http.Handle("/v1", controllers.V1Router)
if err := http.ListenAndServe(":8000", nil); err != nil {
log.Fatal("Serving error.")
}
}
根据评论的回答,我尝试了相同的解决方案,但结果相同:
package main
import (
"net/http"
"log"
"github.com/projectrepo/project/models"
"github.com/projectrepo/project/controllers"
"github.com/gorilla/mux"
)
func main () {
r := mux.NewRouter()
r.Handle("/v1", controllers.V1Router)
if err := http.ListenAndServe(":8000", r); err != nil {
log.Fatal("Serving error.")
}
}
英文:
I'm having some issues with implementing a slight MVC design with gorilla/mux.
The layout of the modules is as follows:
main.go
-- controllers
---- base.controller.go
---- example.controller.go
-- models
---- base.model.go
---- example.controller.go
All the files in controllers
is in the controllers
package, same with models
and then the main.go
is the main
package.
Currently I'm just trying to get the Base Controller
to be able to be shared with the main package
which is working, although it's throwing some errors when trying to implement routes. The build is not throwing any errors, but the routes are not available. If I implement the Walk
function in the Gorilla/Mux documentation to print out all the registered routes for the mux.Router
then it gives me this error:
> &{%!!(MISSING)s(*mux.Router=&{<nil> <nil> [0xc4200901b0] map[] true
> false false false}) %!!(MISSING)s(http.HandlerFunc=0xc8df0)
> [%!!(MISSING)s(*mux.routeRegexp=&{/ false false true false
> 0xc420095360 / [] []})] %!!(MISSING)s(*mux.routeRegexpGroup=&{<nil>
> 0xc420016240 []}) %!!(MISSING)s(bool=true) %!!(MISSING)s(bool=false)
> %!!(MISSING)s(bool=false) %!!(MISSING)s(bool=false) <nil>
> %!!(MISSING)s(mux.BuildVarsFunc=<nil>)}
The reasoning for the global var V1Router *mux.Router
is firstly to access it in the main package
and also to create subrouters in the other controllers.
I am fairly new to Go
, but I'm trying my best to learn the best practices! Any help would be greatly appreciated!
Example code below:
base.controllers.go
package controllers
import (
"fmt"
"bytes"
"net/http"
"github.com/gorilla/mux"
)
var V1Router *mux.Router
func init () {
V1Router = mux.NewRouter()
V1Router.StrictSlash(true)
V1Router.HandleFunc("/", BaseHandler)
}
// Base route to access the API Documentation.
func BaseHandler (w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "Hello, Gophers!")
}
main.go
package main
import (
"net/http"
"log"
"github.com/projectrepo/project/models"
"github.com/projectrepo/project/controllers"
"github.com/gorilla/mux"
)
func main () {
http.Handle("/v1", controllers.V1Router)
if err := http.ListenAndServe(":8000", nil); err != nil {
log.Fatal("Serving error.")
}
}
In response to the comments, I tried this solution with the same result:
package main
import (
"net/http"
"log"
"github.com/projectrepo/project/models"
"github.com/projectrepo/project/controllers"
"github.com/gorilla/mux"
)
func main () {
r := mux.NewRouter()
r.Handle("/v1", controllers.V1Router)
if err := http.ListenAndServe(":8000", r); err != nil {
log.Fatal("Serving error.")
}
}
答案1
得分: 1
Gorilla mux.Router
用于创建一组预定义规则(例如主机、路径、协议、方案等)与其处理程序(http.Handler
或 http.HandlerFunc
)之间的映射。Gorilla mux 可用于替代标准的服务器 mux。如果你将 gorilla/mux
与内置的 http 服务器 mux 结合使用,就像你原来的问题中那样,当客户端访问 /v1
时,实际上会调用 controllers.V1Router
,并将请求路径 /v1
传递给 V1Router1
。在 controllers.V1Router
中,你定义了 /
将由 BaseHandler
处理。然而,由于传入的请求路径是 /v1
,它不会匹配你的路由表。如果你想定义子路由,可以按照以下方式操作(这是我在第一条评论中的意思):
func main () {
r := mux.NewRouter()
v1 := r.PathPrefix("/v1").Subrouter()
controllers.RegisterHandlers(v1)
if err := http.ListenAndServe(":8000", r); err != nil {
log.Fatal("Serving error.")
}
}
然后在控制器文件(base.controllers.go
)中定义:
// 注册处理程序及其子路由
func RegisterHandlers(r *mux.Router) {
// 基本处理程序,即 /v1
r.StrictSlash(true)
r.HandleFunc("/", BaseHandler)
// 示例子路由,即 /v1/example
ex := r.PathPrefix("/example").Subrouter()
ex.HandleFunc("/", ExampleHandler)
// 其他处理程序...
}
英文:
Gorilla mux.Router
is supposed to be used to create mapping between a set of predefined rules (e.g. host, path, protocol, scheme, etc...) and it's handler (http.Handler
or http.HandlerFunc
). Gorilla mux can be used to replace standard server mux. If you combine gorilla/mux
with built in http server mux as your original question, i.e.
func main () {
http.Handle("/v1", controllers.V1Router)
if err := http.ListenAndServe(":8000", nil); err != nil {
log.Fatal("Serving error.")
}
}
what actually happen when a client access /v1
is controllers.V1Router
will be called with request path /v1
passed to V1Router1
. In the controllers.V1Router
, you defined that /
will be handled by BaseHandler
. However, since incoming request path is /v1
, it won't match to your routing table. If you want to define sub routing, you can do as follows (this is what I mean in first comment):
func main () {
r := mux.NewRouter()
v1 := r.PathPrefix("/v1").Subrouter()
controllers.RegisterHandlers(v1)
if err := http.ListenAndServe(":8000", r); err != nil {
log.Fatal("Serving error.")
}
}
Then in the controllers (base.controllers.go
) define
//Register handlers and it's sub router
func RegisterHandlers(r *mux.Router) {
//base handler, i.e. /v1
r.StrictSlash(true)
r.HandleFunc("/", BaseHandler)
//example sub-router, i.e. /v1/example
ex := r.PathPrefix("/example").Subrouter()
ex.HandleFunc("/", ExampleHandler)
//other handlers...
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论