Go中实现多域名路由需自定义Handler解析Host头并分发请求,可为各域名配置独立ServeMux或gorilla/mux路由器,生产环境推荐Nginx/Caddy前置代理。

在 Go 中实现多域名路由(即基于 Host 头的虚拟主机路由),核心是利用 http.ServeMux 的局限性之外的方案——因为标准 http.ServeMux 只匹配路径,不处理 Host。你需要手动解析请求的 Host 字段,并分发到不同处理器。以下是清晰、实用的实现方式。
使用自定义 Handler 实现 Host 分发
最直接的方式是写一个顶层 http.Handler,根据 r.Host(或 r.URL.Host)选择对应子路由。注意:Host 值不含端口(如 example.com),若含端口需用 strings.Split(r.Host, ":")[0] 提取。
- 为每个域名创建独立的
http.ServeMux或第三方路由器(如gorilla/mux、chi) - 在主 handler 中检查
r.Host,匹配后调用对应 mux 的ServeHTTP - 未匹配域名可返回 404 或重定向到默认站点
示例:两个域名分别托管不同服务
以下代码启动一个服务器,让 api.example.com 走 API 路由,www.example.com 走 Web 页面路由:
package main
import (
"fmt"
"net/http"
)
func main() {
apiMux := http.NewServeMux()
apiMux.HandleFunc("/users", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "API: users list")
})
webMux := http.NewServeMux()
webMux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "Web homepage")
})
http.ListenAndServe(":8080", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
host := r.Host
if i := strings.Index(host, ":"); i != -1 {
host = host[:i] // 去掉端口
}
switch host {
case "api.example.com":
apiMux.ServeHTTP(w, r)
case "www.example.com":
webMux.ServeHTTP(w, r)
default:
http.Error(w, "Unknown host", http.StatusNotFound)
}
}))
}
结合 gorilla/mux 支持更复杂路由规则
如果各域名下需要路径参数、中间件、子路由等高级功能,推荐用 gorilla/mux 为每个域名单独建 router:
立即学习“go语言免费学习笔记(深入)”;
- 每个域名对应一个
mux.Router,可独立挂载中间件(如日志、CORS) - 主 handler 不做业务逻辑,只做 Host 路由,保持职责单一
- 支持 TLS 时,确保反向代理(如 Nginx)正确透传 Host 头;若直连,客户端 Host 必须准确
生产环境建议:前置反向代理更可靠
纯 Go 实现 Host 路由可行,但生产中更推荐用 Nginx / Caddy 做虚拟主机分发:
- Nginx 根据
server_name将请求代理到不同 Go 后端端口(如api:8081、web:8082) - Go 服务专注业务,无需处理 Host、HTTPS 终止、负载均衡等
- 便于灰度发布、证书管理、访问日志分离











