用杜松子路由器处理Golang的动态子域的最佳方法是什么?



大家好,

我正在从事一个项目,我需要在其中设置多个子域。我尝试了两个子域的代码,但就我而言,这将是100个子域。我为此尝试了以下代码:

package main
import (
    "github.com/gin-gonic/gin"
    "net/http"
    "strings"
)
type Subdomains map[string]http.Handler
func (subdomains Subdomains) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    domainParts := strings.Split(r.Host, ".")
    if mux := subdomains[domainParts[0]]; mux != nil {
        mux.ServeHTTP(w, r)
    } else {
        http.Error(w, "Not found", 404)
    }
}
func main() {
    r := gin.Default()
    r2 := gin.Default()
    hs := make(Subdomains)
    hs["admin"] = r
    hs["analytics"] = r2
    r.GET("/ping", adminHandlerOne)
    r2.GET("/ping", adminHandlerOne)
    http.ListenAndServe(":9090", hs)
}
func adminHandlerOne(c *gin.Context) {
    c.JSON(200, gin.H{
        "message": "pong",
    })
}

,但我认为这不好。有人知道这样做的正确方法吗?

您可以使用*httputil.ReverseProxy。这是我将基于hostname的子域重新路由,而无需杜松子酒。

中的任何中间件。
router.GET("/:username", func(c *gin.Context) {
    uri, ok := c.Get("location")
    if !ok {
        c.JSON(500, gin.H{
            "reason": "Location unknown",
        })
    }
    hostname := "awesome.io"
    if uri.(*url.URL).Host == hostname {
        // Want to send client to "https://auth.awesome.io/:username"
        s := fmt.Sprintf("https://auth.%s/%s", domain, c.Param("username"))
        uri, err := url.Parse(s)
        if err != nil {
            c.JSON(500, gin.H{
                "reason": "Subdomain is wrong",
            })
        }
        rp := new(httputil.ReverseProxy)
        // Modify request's URL to point to the new uri
        rp.Director = func(req *http.Request) {
            req.URL = uri
        }
        rp.ServeHTTP(c.Writer, c.Request)
    }
})
// Create a subdomainHandler type that implements http.Handler interface
type subdomainHandler struct {
    routers map[string]*gin.Engine // a map of routers for each subdomain
}
// Implement the ServeHTTP method for subdomainHandler
func (s *subdomainHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    // Get the subdomain from the Host header
    host := r.Host
    subdomain := strings.Split(host, ".")[0]
    // Check if there is a router for the subdomain
    if router, ok := s.routers[subdomain]; ok {
        // Use the router to handle the request
        router.ServeHTTP(w, r)
    } else {
        // No router found, return an error
        http.Error(w, "Not found", 404)
    }
}
// Create a newSubdomainHandler function that returns a new subdomainHandler with the given routers
func newSubdomainHandler(routers map[string]*gin.Engine) *subdomainHandler {
    return &subdomainHandler{routers: routers}
}
// In the main function, create different routers for each subdomain and pass them to the newSubdomainHandler function
func main() {
    // Create a router for the main domain
    mainRouter := gin.Default()
    mainRouter.GET("/", func(c *gin.Context) {
        c.String(200, "Welcome to the main domain")
    })
    // Create a router for the admin subdomain
    adminRouter := gin.Default()
    adminRouter.GET("/", func(c *gin.Context) {
        c.String(200, "Welcome to the admin subdomain")
    })
    // Create a router for the blog subdomain
    blogRouter := gin.Default()
    blogRouter.GET("/", func(c *gin.Context) {
        c.String(200, "Welcome to the blog subdomain")
    })
    // Create a map of routers for each subdomain
    routers := map[string]*gin.Engine{
        "":      mainRouter,
        "admin": adminRouter,
        "blog":  blogRouter,
    }
    handler := newSubdomainHandler(routers)
    http.ListenAndServe(":8080", handler)
}

您有几个选项(编写路由器,写包装器,尝试将杜松子酒弯曲到您的意志上),但是由于默认的Servemux支持这一点,而且您可能真的不需要杜松子酒特别是,我会选择标准路由器。首先查看默认设备的来源,以了解路由器的简单性 - 路由器只是通往处理程序的路径的地图。

默认的ServeMux实际上可以执行您想要的操作(允许在主机和路径上匹配),因此我建议您先尝试一下。注册您的模式:

mux := http.NewServeMux()
mux.HandleFunc("/", handlerRoot)
mux.HandleFunc("analytics.example.com/", handlerOne)
mux.HandleFunc("admin.example.com/", handlerTwo)
err := http.ListenAndServe(":9090", mux)
if err != nil {
    panic(err)
}

编写一些处理程序(显然您可以用编码器写JSON,而不是直接编写JSON,这只是一个示例):

func handlerOne(w http.ResponseWriter, r *http.Request) {
    j := fmt.Sprintf(`{"one":"%s"}`, r.Host)
    w.Header().Set("Content-Type", "application/json")
    w.WriteHeader(http.StatusOK)
    w.Write([]byte(j))
}

如果您在Localhost上进行测试,则可能要编辑您的/etc/hosts文件,以确保使用正确的主机名访问服务器。

将其放在一起,您可以使用类似的内容来测试:

https://play.golang.org/p/ut-gt_s3gf

请注意,如果您愿意,这些子域可能是动态的(提及100 Plus会让我认为它们可能是),并且您可以在运行时自定义行为,而不是使用单独的处理程序,这取决于域的行为方式。

相关内容

最新更新