Go 1.16 added the new embed package. I would like to use this package to embed a directory and serve it over HTTP. Consider the following setup:
myproject/
|-- main.go
|-- static/
| |-- index.html
| |-- styles.css
| |-- scripts.js
package main
import (
"embed"
"log"
"net/http"
)
//go:embed static
var staticFS embed.FS
func main() {
http.Handle("/", http.FileServer(http.FS(staticFS)))
log.Fatal(http.ListenAndServe(":8080", nil))
}
With this setup, my expectation is that I can point my browser to localhost:8080
and have it load index.html
. What I am observing instead, is that I need to point my browser to localhost:8080/static
to have it load index.html
.
How can an embedded filesystem be served from the root path of the URL?
When declaring a variable of type embed.FS, that variable represents a filesystem that already contains a root directory. All resources from the //go:embed
directive are copied into this root directory of the filesystem. That means that the staticFS
variable does not refer to the static
folder that was being embedded directly, but to the root directory that contains the static
folder. With that in mind, to achieve the desired result of being able to access the static
folder from localhost:8080
, Go's fs.Sub can be used to pass a filesystem to the server where the static
folder is the root:
package main
import (
"embed"
"io/fs"
"log"
"net/http"
)
//go:embed static
var embeddedFS embed.FS
func main() {
serverRoot, err := fs.Sub(embeddedFS, "static")
if err != nil {
log.Fatal(err)
}
http.Handle("/", http.FileServer(http.FS(serverRoot)))
log.Fatal(http.ListenAndServe(":8080", nil))
}
Alternatively to fs.Sub
you can declare embedding inside the static directory.
package static
//go:embed *.html *.css *.js
var FS embed.FS
And then import it.
package main
import (
"embed"
"log"
"net/http"
"import/path/to/static"
)
func main() {
http.Handle("/", http.FileServer(http.FS(static.FS)))
log.Fatal(http.ListenAndServe(":8080", nil))
}
The downside of adding embedding into static directory is that *.go
file may be also added as embedded unless strict file masks are used (e.g. //go:embed *.html *js
instead of //go:embed *
).
Edit: Removed additionally proposed http.StripPrefix
because it does not actually help with issue.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With