嵌入式目录中的 index.html 在哪里?

Where is index.html in an embedded directory?

我正在尝试 embed 一个静态站点(和 SPA)到我的 Go 代码中。我项目的高层结构是

.
├── web.go
└── spa/
    └── index.html

我的意图是让 http://localhost:8090/ 服务于 index.html

相关代码是

//go:embed spa
var spa embed.FS

log.Info("starting api server")
r := mux.NewRouter()
r.Handle("/", http.FileServer(http.FS(spa)))
log.Fatal(http.ListenAndServe(":8090", r))

访问http://localhost:8090/时,我得到

我该如何设置?

嵌入式目录中的文件路径以 //go:embed 指令中使用的路径为前缀。 index.html 的嵌入式文件系统路径是 spa/index.html.

Create a sub file systemspa 目录为根并为该文件系统提供服务。 index.html在子文件系统中的路径是index.html.

sub, _ := fs.Sub(spa, "spa")
r.Handle("/", http.FileServer(http.FS(sub)))

https://pkg.go.dev/io/fs#Sub

Run an example on the playground.

此方法适用于任何 mux,包括 Gorilla Mux。这是 Gorilla 的代码,其中 r*mux.Router:

sub, _ := fs.Sub(spa, "spa")
r.PathPrefix("/").Handler(http.FileServer(http.FS(sub)))

Run an example on the playground

对于 Gorilla Mux,您需要指定路径前缀:

package main

import (
    "embed"
    "fmt"
    "github.com/gorilla/mux"
    "log"
    "net/http"
)

//go:embed spa
var spa embed.FS

func main() {
    log.Println("starting api server")
    r := mux.NewRouter()
    r.PathPrefix("/spa/").Handler(http.StripPrefix("/", http.FileServer(http.FS(spa))))
    log.Fatal(http.ListenAndServe(":8090", r))
}

这会将对 <host>/spa/* 的请求路由到处理程序。然后你必须去除前缀 / 因为 spa 目录的内容有 spa/ 前缀没有前导 /:

    b, _ := spa.ReadFile("spa/index.html")
    fmt.Println(string(b)) // file contents

总结:

http://localhost:8090/spa/index.html 被路由到 r.PathPrefix("/spa/") 处理程序。虽然路由是 /spa/index.html,但去掉第一个 / 导致 spa/index.html,这最终匹配嵌入变量中的文件路径。