Go中如何基于虚拟主机功能使用FileServer托管静态文件
问题原因
你之前的配置写法存在两个核心问题:
- 混淆了Host匹配和路径匹配的路由规则:
PathPrefix方法仅对请求的URL路径做匹配,不会读取请求头里的Host字段,你把域名写在路径匹配规则里,所有请求的路径都是以/开头,永远无法命中qa.example.com/开头的路径规则,自然路由会被忽略。 - 实现思路存在偏差:虚拟主机的核心逻辑是根据请求携带的Host头做流量分流,不是把域名拼接在路径规则里做匹配。
实现方案
标准库原生实现(无第三方依赖)
- Go 1.22及以上版本:标准库路由已原生支持
主机/路径的匹配模式,可直接绑定FileServer:
package main import ( "net/http" ) func main() { // 直接按Host+路径模式绑定对应静态文件处理器 http.Handle("qa.example.com/", http.FileServer(http.Dir("/static/qa/"))) http.Handle("www.example.com/", http.FileServer(http.Dir("/static/main/"))) http.ListenAndServe(":8080", nil) }
- Go 1.22以下版本:在根处理函数中根据Host字段分流,把请求转发给对应虚拟主机的
FileServer实例即可:
package main import ( "net/http" ) func main() { // 初始化各站点对应的静态文件处理器 qaStaticHandler := http.FileServer(http.Dir("/static/qa/")) mainStaticHandler := http.FileServer(http.Dir("/static/main/")) // 根路由统一做Host分流 http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { switch r.Host { case "qa.example.com": qaStaticHandler.ServeHTTP(w, r) case "www.example.com": mainStaticHandler.ServeHTTP(w, r) default: http.NotFound(w, r) } }) http.ListenAndServe(":8080", nil) }
第三方路由(以gorilla/mux为例)实现
如果使用支持Host匹配的第三方路由库,调用专门的Host匹配方法配置规则即可,不要把域名写入PathPrefix参数:
func initRouter() *mux.Router { r := mux.NewRouter() // 先匹配Host,再匹配路径,绑定对应的FileServer r.Host("qa.example.com").PathPrefix("/").Handler( http.FileServer(http.Dir("/static/qa/")), ) r.Host("www.example.com").PathPrefix("/").Handler( http.FileServer(http.Dir("/static/main/")), ) return r }
注意事项
如果静态文件服务不是挂载在站点根路径,而是挂载在某个子路径(比如/assets/)下,需要使用http.StripPrefix去掉URL里的路径前缀,否则FileServer会在磁盘路径上拼接该前缀,导致404错误,示例:
// qa站点的静态资源通过/assets/路径访问 r.Host("qa.example.com").PathPrefix("/assets/").Handler( http.StripPrefix("/assets/", http.FileServer(http.Dir("/static/qa/"))), )
内容的提问来源于stack exchange,提问作者Igor Chubin
相关产品推荐
相关产品推荐

