如何使用Gorilla Mux实现多子域名托管?
问题描述
需要使用Gorilla Mux实现多子域名托管,支持以下访问路径:
https://www.izzat.com/api/v1/user/gethttps://auth.izzat.com/api/v2/get
以下是我编写的Go代码和Nginx配置,需排查问题并完成适配:
现有Go代码
func NewHttpServer(l logger.Logger, c config.Config, routes []Routes, r *mux.Router) *Http { r.Use(middleware.LoggingMiddleware(l)) v1 := r.Host("www.izzat.com").PathPrefix("/api/v1/").Subrouter() for _, route := range routes { route.InitRoutes(v1) } v2 := r.Host("auth.izzat.com").PathPrefix("/api/v2/").Subrouter() v2.HandleFunc("/get", Test) spa1 := SpaHandler{ IndexPath: "index.html", StaticPath: "web/dist", } r.PathPrefix("/").Handler(spa1) return &Http{ logger: l, config: c, } }
现有Nginx配置
server { listen 80; listen [::]:80; server_name *.izzat.com; access_log /var/log/nginx/access.log; error_log /var/log/nginx/error.log; #ssl_certificate /etc/letsencrypt/live/izzat.com/fullchain.pem; #ssl_certificate_key /etc/letsencrypt/live/izzat.com/privkey.pem; #include /etc/letsencrypt/options-ssl-nginx.conf; #ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; location / { proxy_pass http://myserver.hostname:3000; } }
问题分析与修正方案
1. Nginx核心问题:未传递Host头
默认Nginx反向代理不会将客户端的Host头转发给后端服务,导致Gorilla Mux的Host()子域名匹配规则完全失效。必须在Nginx的location /块中添加头信息配置:
proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme;
2. Gorilla Mux路由优化
- 路径前缀处理:原代码中
PathPrefix("/api/v1/")末尾的斜杠可能导致路径拼接问题,建议改为PathPrefix("/api/v1"),内部注册路由时直接写/user/get即可,避免重复前缀。 - SPA路由隔离:原代码中
r.PathPrefix("/").Handler(spa1)会匹配所有未被捕获的请求,包括子域名的非API路径,建议给SPA路由指定专属Host,避免干扰子域名路由。
修正后的代码示例
修正后的Go代码
func NewHttpServer(l logger.Logger, c config.Config, routes []Routes, r *mux.Router) *Http { r.Use(middleware.LoggingMiddleware(l)) // www子域名的v1 API路由 v1 := r.Host("www.izzat.com").PathPrefix("/api/v1").Subrouter() for _, route := range routes { route.InitRoutes(v1) } // 若routes未注册目标路径,可手动添加示例: // v1.HandleFunc("/user/get", UserGetHandler) // auth子域名的v2 API路由 v2 := r.Host("auth.izzat.com").PathPrefix("/api/v2").Subrouter() v2.HandleFunc("/get", Test) // 仅根域名匹配SPA路由 spaRouter := r.Host("izzat.com").PathPrefix("/").Subrouter() spa1 := SpaHandler{ IndexPath: "index.html", StaticPath: "web/dist", } spaRouter.PathPrefix("/").Handler(spa1) return &Http{ logger: l, config: c, } }
修正后的Nginx配置
server { listen 80; listen [::]:80; server_name *.izzat.com; access_log /var/log/nginx/access.log; error_log /var/log/nginx/error.log; # 启用HTTPS时取消以下注释 #ssl_certificate /etc/letsencrypt/live/izzat.com/fullchain.pem; #ssl_certificate_key /etc/letsencrypt/live/izzat.com/privkey.pem; #include /etc/letsencrypt/options-ssl-nginx.conf; #ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; location / { proxy_pass http://myserver.hostname:3000; # 关键:传递Host头及客户端信息 proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } }
验证步骤
- 重启Nginx和Go服务
- 测试
https://www.izzat.com/api/v1/user/get是否路由到对应处理函数 - 测试
https://auth.izzat.com/api/v2/get是否触发Test函数 - 测试根域名
https://izzat.com是否正常加载SPA页面
内容的提问来源于stack exchange,提问作者нαzιq ιzzαт
相关产品推荐
相关产品推荐

