How to server static files with virtual hosts functioality in Go

huangapple go评论112阅读模式
英文:

How to server static files with virtual hosts functioality in Go

问题

如何在Go中为虚拟主机提供静态文件(使用FileServer)?

如果我有自己的处理函数,这个任务似乎很容易解决[1]:

  1. package main
  2. import (
  3. "fmt"
  4. "net/http"
  5. )
  6. func main() {
  7. http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
  8. fmt.Fprintf(w, "Hello, world!")
  9. })
  10. http.HandleFunc("qa.example.com/", func(w http.ResponseWriter, r *http.Request) {
  11. fmt.Fprintf(w, "Hello, improved world!")
  12. })
  13. http.ListenAndServe(":8080", nil)
  14. }

但是,如果我需要为虚拟主机提供静态文件(使用FileServer),该怎么办?

这个代码片段:

  1. 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]:

  1. package main
  2. import (
  3. "fmt"
  4. "net/http"
  5. )
  6. func main() {
  7. http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
  8. fmt.Fprintf(w, "Hello, world!")
  9. })
  10. http.HandleFunc("qa.example.com/", func(w http.ResponseWriter, r *http.Request) {
  11. fmt.Fprintf(w, "Hello, improved world!")
  12. })
  13. http.ListenAndServe(":8080", nil)
  14. }

But what if I need to serve static files (with FileServer)
for a virtual host?

This

  1. 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

  1. package main
  2. import (
  3. "embed"
  4. "fmt"
  5. "net/http"
  6. "strings"
  7. "time"
  8. )
  9. //go:embed *.go
  10. var f embed.FS
  11. func main() {
  12. // embed.Fs默认使用当前时间或环境变量作为默认修改时间。
  13. now := time.Now()
  14. // 使用主机名映射到http.FileSystem
  15. vhosts := make(map[string]http.FileSystem)
  16. vhosts["qa.example.com"] = http.FS(f) // 来自embed.FS
  17. vhosts["my.example.com"] = http.Dir(".") // 来自http.Dir
  18. http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
  19. fmt.Fprintf(w, "Hello, world!")
  20. })
  21. http.HandleFunc("/static/", func(w http.ResponseWriter, r *http.Request) {
  22. // 查找主机
  23. fs, ok := vhosts[r.Host]
  24. if !ok {
  25. w.WriteHeader(404)
  26. w.Write([]byte("404 not found vhost"))
  27. return
  28. }
  29. // 从http.FileSystem打开文件
  30. file, err := fs.Open(strings.TrimPrefix(r.URL.Path, "/static/"))
  31. if err != nil {
  32. // 参考go1.18.3/net/http/fs.go中的toHTTPError函数处理文件错误。
  33. w.Write([]byte("检查错误是否为403、404或500"))
  34. return
  35. }
  36. stat, _ := file.Stat()
  37. // 修复embed修改时间为零的问题。
  38. modtime := stat.ModTime()
  39. if modtime.IsZero() {
  40. modtime = now
  41. }
  42. // 响应
  43. http.ServeContent(w, r, stat.Name(), modtime, file)
  44. })
  45. http.ListenAndServe(":8080", nil)
  46. }

运行测试执行命令 curl -H "Host: my.example.com" 127.0.0.1:8080/static/01.go,将 01.go 替换为你的静态文件名。

英文:
  1. package main
  2. import (
  3. "embed"
  4. "fmt"
  5. "net/http"
  6. "strings"
  7. "time"
  8. )
  9. //go:embed *.go
  10. var f embed.FS
  11. func main() {
  12. // embed.Fs defaule modtime use now or env value.
  13. now := time.Now()
  14. // use mapping host to http.FileSystem
  15. vhosts := make(map[string]http.FileSystem)
  16. vhosts["qa.example.com"] = http.FS(f) // from embed.FS
  17. vhosts["my.example.com"] = http.Dir(".") // from http.Dir
  18. http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
  19. fmt.Fprintf(w, "Hello, world!")
  20. })
  21. http.HandleFunc("/static/", func(w http.ResponseWriter, r *http.Request) {
  22. // find host
  23. fs, ok := vhosts[r.Host]
  24. if !ok {
  25. w.WriteHeader(404)
  26. w.Write([]byte("404 not found vhost"))
  27. return
  28. }
  29. // open file from http.FileSystem
  30. file, err := fs.Open(strings.TrimPrefix(r.URL.Path, "/static/"))
  31. if err != nil {
  32. // reference go1.18.3/net/http/fs.go toHTTPError function hander file error.
  33. w.Write([]byte("check err is 403 or 404 or 500"))
  34. return
  35. }
  36. stat, _ := file.Stat()
  37. // fix embed modtime is zero.
  38. modtime := stat.ModTime()
  39. if modtime.IsZero() {
  40. modtime = now
  41. }
  42. // response
  43. http.ServeContent(w, r, stat.Name(), modtime, file)
  44. })
  45. http.ListenAndServe(":8080", nil)
  46. }

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/*提供文件服务。

  1. 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/.

  1. http.HandleFunc("qa.example.com/static/", http.StripPrefix("/static", http.FileServer(http.Dir("./static/qa/")))

huangapple
  • 本文由 发表于 2022年6月13日 05:48:42
  • 转载请务必保留本文链接:https://go.coder-hub.com/72596134.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定