【问题标题】:how to organize gorilla mux routes?如何组织 gorilla mux 路线?
【发布时间】:2016-04-05 12:30:07
【问题描述】:

我正在使用 Gorilla Mux 编写 REST API,但我在组织路由时遇到了麻烦,目前我的所有路由都在 main.go 文件中定义,如下所示

//main.go
package main

import (
    "NovAPI/routes"
    "fmt"
    "github.com/gorilla/mux"
    "net/http"
)

func main() {

    router := mux.NewRouter().StrictSlash(true)

    router.HandleFunc("/hello", func(res http.ResponseWriter, req *http.Request) {
        fmt.Fprintln(res, "Hello")
    })

    router.HandleFunc("/user", func(res http.ResponseWriter, req *http.Request) {
        fmt.Fprintln(res, "User")
    })

    router.HandleFunc("/route2", func(res http.ResponseWriter, req *http.Request) {
        fmt.Fprintln(res, "Route2")
    })

    router.HandleFunc("/route3", func(res http.ResponseWriter, req *http.Request) {
        fmt.Fprintln(res, "Route3")
    })

    // route declarations continue like this

    http.ListenAndServe(":1128", router)

}

所以我想要做的是取出这个路由声明并将其拆分为多个文件,我将如何去做呢? 提前致谢。

【问题讨论】:

    标签: go gorilla


    【解决方案1】:

    这样的事情怎么样?

    //main.go
    package main
    
    import (
        "NovAPI/routes"
        "fmt"
        "github.com/gorilla/mux"
        "net/http"
    )
    
    func main() {
    
        router := mux.NewRouter().StrictSlash(true)
    
        router.HandleFunc("/hello", HelloHandler)
        router.HandleFunc("/user", UserHandler)
        router.HandleFunc("/route2", Route2Handler)
        router.HandleFunc("/route3", Route3Handler)
        // route declarations continue like this
    
        http.ListenAndServe(":1128", router)
    
    }
    
    func HelloHandler(res http.ResponseWriter, req *http.Request) {
        fmt.Fprintln(res, "Hello")
    }
    
    func UserHandler(res http.ResponseWriter, req *http.Request) {
        fmt.Fprintln(res, "User")
    }
    
    func Route2Handler(res http.ResponseWriter, req *http.Request) {
        fmt.Fprintln(res, "Route2")
    }
    
    func Route3Handler(res http.ResponseWriter, req *http.Request) {
        fmt.Fprintln(res, "Route3")
    }
    

    这样您就可以将处理程序放在其他文件中,甚至是其他包中。

    如果你最终得到了像数据库这样的额外依赖项,你甚至可以使用构造函数技巧来避免对全局变量的需要:

    //main.go
    
    func main() {
        db := sql.Open(…)
    
        //...
    
        router.HandleFunc("/hello", NewHelloHandler(db))
    
        //...
    }
    
    func NewHelloHandler(db *sql.DB) func(http.ResponseWriter, *http.Request) {
        return func(res http.ResponseWriter, req *http.Request) {
            // db is in the local scope, and you can even inject it to test your
            // handler
            fmt.Fprintln(res, "Hello")
        }
    }
    

    【讨论】:

    • 为了简单起见,我这样做了,但我的处理程序实际上是在 routes 包中定义的,所以我仍然需要将路由从 main 函数中取出
    • 我不明白这一点:无论哪种方式,你仍然要在某个地方写你的路线......如果你的“主要”太长,也许你可以写一个NewRouter帮助将为您初始化它。
    • 另一种解决方案是在你的路由包中有一个初始化函数,它将路由器作为输入并添加它认为合适的路由。但我强烈反对。
    【解决方案2】:

    我喜欢查看 github 中的其他项目以获取有关如何做事的想法,对于这些情况,我通常先查看Docker repo。他们就是这样做的:

    对于system 的路由,在system_routes.go 中定义所有处理程序,然后在system.go 中的NewRouter 函数上初始化这些路由。

    type systemRouter struct {
        backend Backend
        routes  []router.Route
    }
    
    func NewRouter(b Backend) router.Router {
        r := &systemRouter{
            backend: b,
        }
    
        r.routes = []router.Route{
            local.NewOptionsRoute("/", optionsHandler),
            local.NewGetRoute("/_ping", pingHandler),
            local.NewGetRoute("/events", r.getEvents),
            local.NewGetRoute("/info", r.getInfo),
            local.NewGetRoute("/version", r.getVersion),
            local.NewPostRoute("/auth", r.postAuth),
        }
    
        return r
    }
    
    // Routes return all the API routes dedicated to the docker system.
    func (s *systemRouter) Routes() []router.Route {
        return s.routes
    }
    

    注意systemRouter实现了router.Router接口,Routes函数返回一个[]router.Route,它们的handler定义为

    func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error
    

    代替 Go 的标准 http 处理程序:

    func(w http.ResponseWriter, r *http.Request)
    

    所以他们的额外代码可以在makeHttpHandler 函数中将 Docker API 处理程序转换为 Go HTTP 处理程序。

    最后,为了将这些路由添加到他们的多路复用路由器,在他们的 server.go 上,他们实现了几个其他函数到 add middleware 到他们的处理程序。

    如果您认为这是您正在寻找的东西,那么请花点时间分析 Docker 代码中的路线,如果您需要我详细说明或者如果我遗漏了任何内容,请发表评论。

    【讨论】:

      【解决方案3】:

      您可以将您的路由器独立模块化成不同的包,并将它们安装在主路由器上

      在下面的issue 上稍微详细说明一下,您可以提出这种方法,这使得它非常可扩展(并且在某种程度上更容易测试)

      /api/router.go

      package api
      
      import (
          "net/http"
      
          "github.com/gorilla/mux"
      )
      
      func Router() *mux.Router {
          router := mux.NewRouter()
          router.HandleFunc("/", home)
          return router
      }
      
      func home(w http.ResponseWriter, req *http.Request) {
          w.Write([]byte("hello from API"))
      }
      

      /main.go

      package main
      
      import (
          "log"
          "net/http"
          "strings"
      
          "github.com/...yourPath.../api"
          "github.com/...yourPath.../user"
          "github.com/gorilla/mux"
      )
      
      func main() {
          router := mux.NewRouter()
      
          router.HandleFunc("/", home)
          mount(router, "/api", api.Router())
          mount(router, "/user", user.Router())
      
          log.Fatal(http.ListenAndServe(":8080", router))
      }
      
      func mount(r *mux.Router, path string, handler http.Handler) {
          r.PathPrefix(path).Handler(
              http.StripPrefix(
                  strings.TrimSuffix(path, "/"),
                  handler,
              ),
          )
      }
      
      func home(w http.ResponseWriter, req *http.Request) {
          w.Write([]byte("Home"))
      }
      

      【讨论】:

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