有时需要在一个应用中运行多个 HTTP 服务器,比如管理接口和业务接口分离。
package main
import (
"log"
"net/http"
"github.com/gin-gonic/gin"
)
func main() {
api := gin.Default()
api.GET("/", func(c *gin.Context) {
c.String(200, "API Server")
})
admin := gin.Default()
admin.GET("/", func(c *gin.Context) {
c.String(200, "Admin Server")
})
go func() {
log.Println("API server on :8080")
api.Run(":8080")
}()
go func() {
log.Println("Admin server on :8081")
admin.Run(":8081")
}()
select {}
}
func main() {
api := gin.Default()
api.GET("/api", func(c *gin.Context) {
c.JSON(200, gin.H{"server": "api"})
})
admin := gin.Default()
admin.GET("/admin", func(c *gin.Context) {
c.JSON(200, gin.H{"server": "admin"})
})
apiServer := &http.Server{
Addr: ":8080",
Handler: api,
}
adminServer := &http.Server{
Addr: ":8081",
Handler: admin,
}
go func() {
apiServer.ListenAndServe()
}()
go func() {
adminServer.ListenAndServe()
}()
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
<-quit
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
apiServer.Shutdown(ctx)
adminServer.Shutdown(ctx)
}
func CommonMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
start := time.Now()
c.Next()
log.Printf("%s %s - %v", c.Request.Method, c.Request.URL.Path, time.Since(start))
}
}
func main() {
common := gin.New()
common.Use(CommonMiddleware())
api := common.Group("/api")
api.GET("/users", func(c *gin.Context) {
c.JSON(200, gin.H{"users": []string{"张三", "李四"}})
})
admin := common.Group("/admin")
admin.GET("/stats", func(c *gin.Context) {
c.JSON(200, gin.H{"stats": "ok"})
})
common.Run(":8080")
}
func main() {
public := gin.Default()
public.GET("/", func(c *gin.Context) {
c.String(200, "Public API")
})
internal := gin.New()
internal.Use(gin.Recovery())
internal.GET("/", func(c *gin.Context) {
c.String(200, "Internal API")
})
publicServer := &http.Server{
Addr: ":8080",
Handler: public,
ReadTimeout: 10 * time.Second,
WriteTimeout: 10 * time.Second,
}
internalServer := &http.Server{
Addr: ":8081",
Handler: internal,
ReadTimeout: 30 * time.Second,
WriteTimeout: 30 * time.Second,
}
go publicServer.ListenAndServe()
go internalServer.ListenAndServe()
select {}
}
type SharedState struct {
mu sync.RWMutex
Counter int
}
func main() {
state := &SharedState{}
api := gin.Default()
api.GET("/increment", func(c *gin.Context) {
state.mu.Lock()
state.Counter++
state.mu.Unlock()
c.JSON(200, gin.H{"counter": state.Counter})
})
admin := gin.Default()
admin.GET("/stats", func(c *gin.Context) {
state.mu.RLock()
counter := state.Counter
state.mu.RUnlock()
c.JSON(200, gin.H{"counter": counter})
})
go api.Run(":8080")
go admin.Run(":8081")
select {}
}
func setupRoutes(r *gin.Engine, prefix string) {
r.GET(prefix+"/health", func(c *gin.Context) {
c.JSON(200, gin.H{"status": "ok"})
})
r.GET(prefix+"/info", func(c *gin.Context) {
c.JSON(200, gin.H{"version": "1.0.0"})
})
}
func main() {
api := gin.Default()
setupRoutes(api, "/api")
admin := gin.Default()
setupRoutes(admin, "/admin")
go api.Run(":8080")
go admin.Run(":8081")
select {}
}
多路由器适合需要不同端口、不同配置的场景。使用 http.Server 可以更精细地控制服务器行为。注意共享数据时的并发安全,以及优雅关闭所有服务器。