Sharing a gorilla/mux router across packages

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

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 (
		&quot;fmt&quot;
		&quot;bytes&quot;
		&quot;net/http&quot;
		&quot;github.com/gorilla/mux&quot;
)

var V1Router *mux.Router

func init () {
	V1Router = mux.NewRouter()
	V1Router.StrictSlash(true)
	V1Router.HandleFunc(&quot;/&quot;, BaseHandler)    
}

// Base route to access the API Documentation.
func BaseHandler (w http.ResponseWriter, r *http.Request) {
	fmt.Fprint(w, &quot;Hello, Gophers!&quot;)
}

main.go

package main

import (
    &quot;net/http&quot;
    &quot;log&quot;
    &quot;github.com/projectrepo/project/models&quot;
	&quot;github.com/projectrepo/project/controllers&quot;
	&quot;github.com/gorilla/mux&quot;
)

func main () {
    http.Handle(&quot;/v1&quot;, controllers.V1Router)
    if err := http.ListenAndServe(&quot;:8000&quot;, nil); err != nil {
        log.Fatal(&quot;Serving error.&quot;)
    }
}

In response to the comments, I tried this solution with the same result:

package main

import (
    &quot;net/http&quot;
    &quot;log&quot;
    &quot;github.com/projectrepo/project/models&quot;
    &quot;github.com/projectrepo/project/controllers&quot;
    &quot;github.com/gorilla/mux&quot;
)

func main () {
    r := mux.NewRouter()
    r.Handle(&quot;/v1&quot;, controllers.V1Router)
    if err := http.ListenAndServe(&quot;:8000&quot;, r); err != nil {
        log.Fatal(&quot;Serving error.&quot;)
    }
}

答案1

得分: 1

Gorilla mux.Router 用于创建一组预定义规则(例如主机、路径、协议、方案等)与其处理程序(http.Handlerhttp.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(&quot;/v1&quot;, controllers.V1Router)
    if err := http.ListenAndServe(&quot;:8000&quot;, nil); err != nil {
        log.Fatal(&quot;Serving error.&quot;)
    }
}

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(&quot;/v1&quot;).Subrouter()
    controllers.RegisterHandlers(v1)

    if err := http.ListenAndServe(&quot;:8000&quot;, r); err != nil {
        log.Fatal(&quot;Serving error.&quot;)
    }
}

Then in the controllers (base.controllers.go) define

//Register handlers and it&#39;s sub router
func RegisterHandlers(r *mux.Router) {
    //base handler, i.e. /v1
    r.StrictSlash(true)
    r.HandleFunc(&quot;/&quot;, BaseHandler)

    //example sub-router, i.e. /v1/example
    ex := r.PathPrefix(&quot;/example&quot;).Subrouter()
    ex.HandleFunc(&quot;/&quot;, ExampleHandler)

    //other handlers...
}

huangapple
  • 本文由 发表于 2017年6月6日 19:04:18
  • 转载请务必保留本文链接:https://go.coder-hub.com/44388292.html
匿名

发表评论

匿名网友

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

确定