大家好,
我正在从事一个项目,我需要在其中设置多个子域。我尝试了两个子域的代码,但就我而言,这将是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会让我认为它们可能是),并且您可以在运行时自定义行为,而不是使用单独的处理程序,这取决于域的行为方式。