在Golang的Web服务开发中,多域名路由支持虚拟主机访问的核心是根据接收到的HTTP请求中的Host头部信息,将不同的域名请求分发到对应的业务逻辑处理函数中,从而实现单个服务实例承载多个不同域名的站点服务。

核心实现思路
实现多域名路由支持虚拟主机访问主要分为三个步骤:首先获取请求中的Host信息,然后根据预设的域名与处理函数的映射关系匹配对应的处理逻辑,最后执行匹配到的处理函数并返回响应。Golang标准库的net/http包提供了足够的扩展能力,我们可以通过自定义http.Handler来实现这一逻辑。
基础实现示例
下面是一个简单的多域名路由实现示例,支持两个不同域名的虚拟主机访问:
package main
import (
"fmt"
"net/http"
)
// 定义域名到处理函数的映射
var domainHandlers = map[string]http.HandlerFunc{
"blog.ipipp.com": func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "欢迎访问博客站点,当前路径:%s", r.URL.Path)
},
"shop.ipipp.com": func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "欢迎访问商城站点,当前路径:%s", r.URL.Path)
},
}
// 自定义多域名路由处理器
type MultiDomainRouter struct{}
func (m *MultiDomainRouter) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// 获取请求的Host信息,去除端口号
host := r.Host
for i := 0; i < len(host); i++ {
if host[i] == ':' {
host = host[:i]
break
}
}
// 匹配域名对应的处理函数
if handler, ok := domainHandlers[host]; ok {
handler(w, r)
return
}
// 没有匹配的域名返回404
http.NotFound(w, r)
}
func main() {
router := &MultiDomainRouter{}
// 监听8080端口
http.ListenAndServe(":8080", router)
}
结合现有路由库扩展
如果项目中已经使用了第三方路由库比如gorilla/mux,可以在自定义处理器中结合路由库的能力,为每个域名单独创建路由实例:
package main
import (
"fmt"
"net/http"
"github.com/gorilla/mux"
)
// 为每个域名创建独立的路由实例
func createBlogRouter() *mux.Router {
r := mux.NewRouter()
r.HandleFunc("/article/{id}", func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
fmt.Fprintf(w, "博客文章ID:%s", vars["id"])
})
return r
}
func createShopRouter() *mux.Router {
r := mux.NewRouter()
r.HandleFunc("/goods/{id}", func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
fmt.Fprintf(w, "商城商品ID:%s", vars["id"])
})
return r
}
// 域名到路由实例的映射
var domainRouters = map[string]*mux.Router{
"blog.ipipp.com": createBlogRouter(),
"shop.ipipp.com": createShopRouter(),
}
type MultiDomainMuxRouter struct{}
func (m *MultiDomainMuxRouter) ServeHTTP(w http.ResponseWriter, r *http.Request) {
host := r.Host
for i := 0; i < len(host); i++ {
if host[i] == ':' {
host = host[:i]
break
}
}
if router, ok := domainRouters[host]; ok {
router.ServeHTTP(w, r)
return
}
http.NotFound(w, r)
}
func main() {
http.ListenAndServe(":8080", &MultiDomainMuxRouter{})
}
注意事项
- 生产环境中建议对Host信息做合法性校验,避免恶意请求伪造Host头部绕过路由匹配。
- 如果服务部署在反向代理后面,需要正确配置反向代理的Host转发规则,确保后端服务能获取到真实的请求域名。
- 域名映射关系可以放到配置文件或者配置中心,避免硬编码导致修改时需要重新编译服务。
- 如果需要支持泛域名匹配,比如
*.ipipp.com都指向同一个处理逻辑,可以在匹配Host时做前缀或者后缀判断。
泛域名匹配示例
下面是支持泛域名匹配的扩展实现:
package main
import (
"fmt"
"net/http"
"strings"
)
var wildcardHandler = func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "泛域名访问,当前域名:%s", r.Host)
}
type WildcardDomainRouter struct{}
func (w *WildcardDomainRouter) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
host := r.Host
for i := 0; i < len(host); i++ {
if host[i] == ':' {
host = host[:i]
break
}
}
// 先匹配精确域名
exactHandlers := map[string]http.HandlerFunc{
"admin.ipipp.com": func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "管理后台站点")
},
}
if handler, ok := exactHandlers[host]; ok {
handler(rw, r)
return
}
// 匹配泛域名 *.ipipp.com
if strings.HasSuffix(host, ".ipipp.com") {
wildcardHandler(rw, r)
return
}
http.NotFound(rw, r)
}
func main() {
http.ListenAndServe(":8080", &WildcardDomainRouter{})
}
Golang多域名路由虚拟主机http_router修改时间:2026-06-19 18:12:20