英文:
How to server static files with virtual hosts functioality in Go
问题
如何在Go中为虚拟主机提供静态文件(使用FileServer
)?
如果我有自己的处理函数,这个任务似乎很容易解决[1]:
package main
import (
"fmt"
"net/http"
)
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, world!")
})
http.HandleFunc("qa.example.com/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, improved world!")
})
http.ListenAndServe(":8080", nil)
}
但是,如果我需要为虚拟主机提供静态文件(使用FileServer
),该怎么办?
这个代码片段:
r.PathPrefix("qa.example.com/").Handler(http.FileServer(http.Dir("/static/qa/")))
不起作用 - 它被忽略了。
我做错了什么?
这种方法一般是错误的吗?
英文:
How can I server static files (with FileServer
) for a virtual host in Go?
If I have my own handler function, the task seems to be easily solvable [1]:
package main
import (
"fmt"
"net/http"
)
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, world!")
})
http.HandleFunc("qa.example.com/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, improved world!")
})
http.ListenAndServe(":8080", nil)
}
But what if I need to serve static files (with FileServer
)
for a virtual host?
This
r.PathPrefix("qa.example.com/").Handler(http.FileServer(http.Dir("/static/qa/")))
does not work — it is just ignored.
What am I doing wrong?
Is this approach generally wrong?
答案1
得分: 2
package main
import (
"embed"
"fmt"
"net/http"
"strings"
"time"
)
//go:embed *.go
var f embed.FS
func main() {
// embed.Fs默认使用当前时间或环境变量作为默认修改时间。
now := time.Now()
// 使用主机名映射到http.FileSystem
vhosts := make(map[string]http.FileSystem)
vhosts["qa.example.com"] = http.FS(f) // 来自embed.FS
vhosts["my.example.com"] = http.Dir(".") // 来自http.Dir
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, world!")
})
http.HandleFunc("/static/", func(w http.ResponseWriter, r *http.Request) {
// 查找主机
fs, ok := vhosts[r.Host]
if !ok {
w.WriteHeader(404)
w.Write([]byte("404 not found vhost"))
return
}
// 从http.FileSystem打开文件
file, err := fs.Open(strings.TrimPrefix(r.URL.Path, "/static/"))
if err != nil {
// 参考go1.18.3/net/http/fs.go中的toHTTPError函数处理文件错误。
w.Write([]byte("检查错误是否为403、404或500"))
return
}
stat, _ := file.Stat()
// 修复embed修改时间为零的问题。
modtime := stat.ModTime()
if modtime.IsZero() {
modtime = now
}
// 响应
http.ServeContent(w, r, stat.Name(), modtime, file)
})
http.ListenAndServe(":8080", nil)
}
运行测试执行命令 curl -H "Host: my.example.com" 127.0.0.1:8080/static/01.go
,将 01.go
替换为你的静态文件名。
英文:
package main
import (
"embed"
"fmt"
"net/http"
"strings"
"time"
)
//go:embed *.go
var f embed.FS
func main() {
// embed.Fs defaule modtime use now or env value.
now := time.Now()
// use mapping host to http.FileSystem
vhosts := make(map[string]http.FileSystem)
vhosts["qa.example.com"] = http.FS(f) // from embed.FS
vhosts["my.example.com"] = http.Dir(".") // from http.Dir
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, world!")
})
http.HandleFunc("/static/", func(w http.ResponseWriter, r *http.Request) {
// find host
fs, ok := vhosts[r.Host]
if !ok {
w.WriteHeader(404)
w.Write([]byte("404 not found vhost"))
return
}
// open file from http.FileSystem
file, err := fs.Open(strings.TrimPrefix(r.URL.Path, "/static/"))
if err != nil {
// reference go1.18.3/net/http/fs.go toHTTPError function hander file error.
w.Write([]byte("check err is 403 or 404 or 500"))
return
}
stat, _ := file.Stat()
// fix embed modtime is zero.
modtime := stat.ModTime()
if modtime.IsZero() {
modtime = now
}
// response
http.ServeContent(w, r, stat.Name(), modtime, file)
})
http.ListenAndServe(":8080", nil)
}
run test exec command curl -H "Host: my.example.com" 127.0.0.1:8080/static/01.go
, 01.go
replacte your static filename.
答案2
得分: 0
为host/path
注册一个处理程序。仅在调用文件处理程序时去除/path
部分。
此注册将从目录./static/qa/
为qa.example.com/static/*
提供文件服务。
http.HandleFunc("qa.example.com/static/", http.StripPrefix("/static", http.FileServer(http.Dir("./static/qa/"))))
英文:
Register a handler for host/path
. Strip the /path
part only when invoking the file handler.
This registration serves files for qa.example.com/static/*
from the directory ./static/qa/
.
http.HandleFunc("qa.example.com/static/", http.StripPrefix("/static", http.FileServer(http.Dir("./static/qa/")))
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论