【问题标题】:Sharing a gorilla/mux router across packages跨包共享 gorilla/mux 路由器
【发布时间】:2017-11-07 08:51:37
【问题描述】:

我在使用 gorilla/mux 实现轻微的 MVC 设计时遇到了一些问题。

模块布局如下:

main.go
-- controllers
---- base.controller.go
---- example.controller.go
-- models
---- base.model.go
---- example.controller.go

controllers 中的所有文件都在controllers 包中,models 相同,然后main.gomain 包。

目前我只是想让Base Controller 能够与正在工作的main package 共享,尽管它在尝试实现路由时会引发一些错误。构建没有抛出任何错误,但路由不可用。如果我在 Gorilla/Mux 文档中实现 Walk 函数以打印出 mux.Router 的所有注册路由,那么它会给我这个错误:

&{%!!(MISSING)s(*mux.Router=&{ [0xc4200901b0] map[] true 假假假}) %!!(MISSING)s(http.HandlerFunc=0xc8df0) [%!!(MISSING)s(*mux.routeRegexp=&{/ 假假真假 0xc420095360 / [] []})] %!!(MISSING)s(*mux.routeRegexpGroup=&{ 0xc420016240 []}) %!!(MISSING)s(bool=true) %!!(MISSING)s(bool=false) %!!(MISSING)s(bool=false) %!!(MISSING)s(bool=false) %!!(MISSING)s(mux.BuildVarsFunc=)}

全局var V1Router *mux.Router的原因是首先在main package中访问它,并且在其他控制器中创建子路由器。

我对@9​​87654334@ 还很陌生,但我正在努力学习最佳实践!任何帮助将不胜感激!

示例代码如下:

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

针对cmets,我尝试了这个解决方案,结果相同:

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

【问题讨论】:

  • 您不能混合使用标准多路复用器 (http.DefaultServerMux) 和 gorilla/mux。如果您不想替换标准参数,则应将gorilla router 作为http.ListenAndServe 的第二个参数传递。你的控制器的路径是什么样子的?
  • @putu 我现在所做的是在main package 中添加了一个默认的r := mux.NewRouter(),并将/v1/ 处理为controllers.V1Router(),我得到了一个零指针错误。我确实添加了r 来替换ListenAndServe 中的nil
  • @putu 好的,那是我的错误 - 我在调试时出错。以原来的方式修复所有内容我得到了同样的错误。
  • 我的第一条评论可能不是 100% 正确的。您可以混合使用它,只有通过http.Handle("/", controllers.V1Router) 注册它或将其作为http.ListenAndServe 的第二个参数传递它才有效。 /v1 的子路由器必须使用 Route.Subrouter 创建,例如v1 := V1Router.PathPrefix("/v1").Subrouter(),然后将基本控制器注册到v1
  • @putu,您评论的第一部分 - 这与我第一次尝试的解决方案不同吗?

标签: go gorilla


【解决方案1】:

Gorilla mux.Router 应该用于在一组预定义规则(例如主机、路径、协议、方案等)和它的处理程序(http.Handlerhttp.HandlerFunc)之间创建映射。 Gorilla 多路复用器可用于替代标准服务器多路复用器。如果您将 gorilla/mux 与内置 http 服务器多路复用器结合为您的原始问题,即

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

当客户端访问/v1controllers.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) 中定义

//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...
}

【讨论】:

  • 谢谢!这是一个很好的解释。我已经编辑了我的结构并且效果很好。 :)
猜你喜欢
  • 2014-09-08
  • 2016-04-07
  • 1970-01-01
  • 2015-06-17
  • 1970-01-01
  • 1970-01-01
  • 2016-04-26
  • 1970-01-01
  • 2017-11-09
相关资源
最近更新 更多