用GIN路由器处理Golang中动态子域的最佳方法是什么

uqjltbpv  于 2023-08-01  发布在  Go
关注(0)|答案(3)|浏览(102)

大家好,
我在一个项目上工作,我需要设置多个子域的路线。我尝试了两个子域的代码,但在我的情况下,它将是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",
    })
}

字符串
但我觉得这样不好。有人知道正确的方法吗?

ws51t4hk

ws51t4hk1#

你可以使用*httputil.ReverseProxy来实现。下面是我如何在没有任何Gin中间件的情况下基于主机名重路由到子域。

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

字符串

new9mtju

new9mtju2#

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

字符串

pw136qt2

pw136qt23#

你有几个选择(写一个路由器,写 Package 器,试图弯曲杜松子酒你的意志),但作为默认的ServeMux支持这一点,你可能真的不需要杜松子酒,特别是,我会去与标准路由器。首先看一下DefaultServeMux的源代码,了解路由器的本质有多简单--路由器只是到处理程序的路径Map。
默认的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,这只是一个例子):

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多个让我觉得它们可能是动态的),你可以在运行时在处理程序中自定义行为,而不是使用单独的处理程序,这取决于域的行为有多不同。

相关问题