如何使用gorilla/mux将URL拆分为多个文件?

5

我的目录结构如下:

myapp/
|
+-- moduleX
|      |
|      +-- views.go
|
+-- start.go

这个应用程序使用start.go启动,然后我从那里配置所有的路由并从moduleX/views.go导入处理程序,代码如下:

package main

import (
    "net/http"
    "github.com/gorilla/mux"
    "myapp/moduleX"
)

func main() {
    r := mux.NewRouter()
    http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("./templates/static/"))))
    r.HandleFunc("/", moduleX.SomePostHandler).Methods("POST")
    r.HandleFunc("/", moduleX.SomeHandler)
    http.Handle("/", r)
    http.ListenAndServe(":8080", nil)
}

现在我想添加更多的模块,并询问自己是否(以及如何)可以在urls.go文件中定义模块的URL,并在start.go中“导入”它们。具体地说,我希望start.go只需一次导入或某种module.GetURLs函数即可知道所有somemodule/urls.go文件中的URL。
2个回答

4

为什么不让处理程序自己插入路由表呢?

如果您在单独的go文件中定义每个处理程序,请使用每个文件的`init()`函数将处理程序添加到全局路由表中。

所以大致如下:


main.go:

type route{
    method string
    path string
    handler func(w http.ResponseWriter, r *http.Request)
}
var routes = make([]route,0)

func registerRoute(r route){
    routes = append(routes,r)
}

func server(){
    r := mux.NewRouter()
    http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("./templates/static/"))))
    // set up all the registered routes
    for _, rt = range(routes){
        r.HandleFunc(rt.path,rt.handler).Methods(rt.Method)
    }
    // and there's usually some other stuff that needs to go in here

    //before we finally serve the content here!
    http.ListenAndServe(":8080", nil)
}

yourmodule.go:

func init(){
    r = route{
        method="GET",
        path="/yourmodule/path/whatever",
        handler=yourHandlerFunc,
    }
    registerRoute(r)
}

func yourHandlerFunc(w http.ResponseWriter, r *http.Request){
    //awesome web stuff goes here
}

在执行包的main()之前,对于包中的每个文件都会调用init()函数,因此您可以确保在启动服务器之前所有的处理程序都已注册。

可以将此模式扩展以允许根据需要进行更多的特殊注册处理。由于现在模块本身负责其自身的注册,而不是试图将所有特殊情况压缩到一个注册函数中,因此这一点是可能的。


太好了!我会尝试一下。如果每个模块都完全负责自己的路由,那么这是更好的解决方案。 - Subito
谢谢您发布这篇文章,对我帮助很大! - Campbell_Souped

3

编辑:

要一次创建一组mux.Route,您可以定义一个自定义类型(在下面的示例中为handler),然后执行以下操作:

package main

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

type handler struct {
    path    string
    f       http.HandlerFunc
    methods []string
}

func makeHandlers(hs []handler, r *mux.Router) {
    for _, h := range hs {
        if len(h.methods) == 0 {
            r.HandleFunc(h.path, h.f)
        } else {
            r.HandleFunc(h.path, h.f).Methods(h.methods...)
        }
    }
}

// create some example handler functions

func somePostHandler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprint(w, "POST Handler")
}

func someHandler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprint(w, "Normal Handler")
}

func main() {
    //define some handlers
    handlers := []handler{{path: "/", f: somePostHandler, methods: []string{"POST"}}, {path: "/", f: someHandler}}
    r := mux.NewRouter()
    http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("./templates/static/"))))
    // Initialise the handlers
    makeHandlers(handlers, r)
    http.Handle("/", r)
    http.ListenAndServe(":8080", nil)
}

游乐场

如果它们在同一包中,您就不需要import它们。

您可以在urls.go中定义URL变量,然后在views.go(或package moduleX中的另一个文件)中编写逻辑,只要它们具有相同的package声明。

例如:

// moduleX/urls.go

package moduleX

var (
    urls = []string{"http://google.com/", "http://stackoverflow.com/"}
)

然后:

// moduleX/views.go (or some other file in package moduleX)

package moduleX

func GetUrls() []string {
    return urls
}

然后:

// start.go

package main

import (
    "fmt"
    "myapp/moduleX"
)

func main() {
    for _, url := range moduleX.GetUrls() {
        fmt.Println(url)
    }
}

或者更简单的方法,只需将变量从moduleX包中导出,赋予一个大写名称即可。
例如:
// moduleX/urls.go

package moduleX

var URLs = []string{"http://google.com/", "http://stackoverflow.com/"}

然后:
// start.go

package main    

import (
    "fmt"
    "myapp/moduleX"
)

func main() {
    for _, url := range moduleX.URLs {
        fmt.Println(url)
    }
}

请看任意一个Go源代码,了解它们如何处理相同的问题。一个好的例子在SHA512源代码中,其中长变量存储在sha512block.go中,逻辑在sha512.go中。

这是可行的,我知道这是可能的 - 但它并不能直接解决我的问题。即使我将所有URL导出到start.go,我如何为它们创建具有适当处理程序的路由?我想在moduleX / urls.go中执行所有HandleFunc()-stuff,然后在start.go中“使用”这些路由器(或路由或HandleFuncs?)。对于一个模块,我可以在urls.go中定义路由器并在start.go中使用它们,但对于多个模块,我需要一种“附加”到路由器的方法。 - Subito
1
创建一个URL到http.HandlerFunc的映射,然后创建一个函数来将它们全部初始化为mux.Route - Intermernet
好的,现在我做了这样的事情:在我的urls.go中写了以下代码:func GetRoutes() []core.Route { routes := []core.Route{ core.Route{URL: "/new/", Handler: NewObjHandler}, core.Route{URL: "/", Handler: login.LoginFirst(ListObjHandler)}, } return routes }然后在我的代码中加入了以下内容:obj_routes := obj.GetRoutes() s := r.PathPrefix("/obj/").Subrouter() for _, route := range obj_routes { s.HandleFunc(route.URL, route.Handler) }这段代码可以工作,但看起来很丑。我不知道如何使用gorillas mux中的.Methods("POST") - Subito
太好了,你的makeHandlers是Methods()无法工作的关键所在。对我来说很有效。唯一剩下的问题是:我必须为每个模块编写module.GetRoutes()makeHandlers(moduleRoutes, subrouter)。我猜没有其他办法了吧? - Subito
听起来你想要定义一个模块接口。如果每个模块都呈现出相同的一组导出方法,你可以为这些方法定义一个接口,然后将它们全部视为相同的。请查看http://golang.org/doc/effective_go.html#interfaces。 - Intermernet
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接