gin-gonic / gin

Gin is a HTTP web framework written in Go (Golang). It features a Martini-like API with much better performance -- up to 40 times faster. If you need smashing performance, get yourself some Gin.
https://gin-gonic.com/
MIT License
78.88k stars 8.02k forks source link

How can I use subdomain specific routers? #2960

Open rew1nter opened 2 years ago

rew1nter commented 2 years ago

Is this how its supposed to be done?

package main

import (
    "log"
    "net/http"
    "time"

    "github.com/gin-gonic/gin"
    "golang.org/x/sync/errgroup"
)

var (
    g errgroup.Group
)

func router01() http.Handler {
    e := gin.New()
    e.Use(gin.Recovery())
    e.GET("/", func(c *gin.Context) {
        c.JSON(
            http.StatusOK,
            gin.H{
                "code":  http.StatusOK,
                "error": "Welcome server 01",
            },
        )
    })

    return e
}

func router02() http.Handler {
    e := gin.New()
    e.Use(gin.Recovery())
    e.GET("/", func(c *gin.Context) {
        c.JSON(
            http.StatusOK,
            gin.H{
                "code":  http.StatusOK,
                "error": "Welcome server 02",
            },
        )
    })

    return e
}

func main() {
    server01 := &http.Server{
        Addr:         "y.domain.com:80",
        Handler:      router01(),
        ReadTimeout:  5 * time.Second,
        WriteTimeout: 10 * time.Second,
    }

    server02 := &http.Server{
        Addr:         "x.domain.com:80",
        Handler:      router02(),
        ReadTimeout:  5 * time.Second,
        WriteTimeout: 10 * time.Second,
    }

    g.Go(func() error {
        err := server01.ListenAndServe()
        if err != nil && err != http.ErrServerClosed {
            log.Fatal(err)
        }
        return err
    })

    g.Go(func() error {
        err := server02.ListenAndServe()
        if err != nil && err != http.ErrServerClosed {
            log.Fatal(err)
        }
        return err
    })

    if err := g.Wait(); err != nil {
        log.Fatal(err)
    }
}
tsln1998 commented 2 years ago

You can implement this function very simply:

// main.go
package main

import (
    "example-project/subdomain"
    "github.com/gin-gonic/gin"
    "net/http"
)

func main() {
    serverA := gin.Default()
    serverA.GET("/", func(c *gin.Context) {
        c.String(http.StatusOK, "A")
    })

    serverB := gin.Default()
    serverB.GET("/", func(c *gin.Context) {
        c.String(http.StatusOK, "B")
    })

    serverDefault := gin.Default()
    serverDefault.GET("/", func(c *gin.Context) {
        c.String(http.StatusOK, "Default")
    })

    _ = http.ListenAndServe(":8081",
        subdomain.NewSubdomainHandler().
            On("a.example.com", serverA).
            On("b.example.com", serverB).
            Default(serverDefault),
    )
}
// subdomain/subdomain.go
package subdomain

import (
    "net/http"
)

type subdomainHandler struct {
    handlers map[string]http.Handler
}

func NewSubdomainHandler() *subdomainHandler {
    return &subdomainHandler{handlers: make(map[string]http.Handler, 32)}
}

func (s *subdomainHandler) On(domain string, handler http.Handler) *subdomainHandler {
    s.handlers[domain] = handler
    return s
}
func (s *subdomainHandler) Default(handler http.Handler) *subdomainHandler {
    return s.On("", handler)
}

func (s *subdomainHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    if h, ok := s.handlers[r.Host]; ok {
        h.ServeHTTP(w, r)
        return
    }
    if h, ok := s.handlers[""]; ok {
        h.ServeHTTP(w, r)
        return
    }
    http.NotFound(w, r)
}

Now, run your program and test it with curl 👇🏻

$ curl -x http://localhost:8081 http://a.example.com
A
$ curl -x http://localhost:8081 http://b.example.com
B
$ curl -x http://localhost:8081 http://c.example.com
Default