Serving a godoc vfs.FileSystem with http.FileServer
The short version: See https://godoc.org/bitbucket.org/mjl/httpvfs for a tiny library that makes it easy to use net/http’s FileServer() on a vfs.FileSystem from godoc.
The longer version: I’ve been writing a few HTTP services in Go again. The “asset” library has been very useful in making fat binaries, resulting in a single file that contains all static assets too. See https://godoc.org/bitbucket.org/mjl/asset. It appends a zip file to a binary, then uses godoc’s zipfs to read files from the embedded zip file. Zipfs is a vfs.FileSystem, so that is what the asset library uses too.
So, I noticed I kept writing a function to serve static file from a vfs.FileSystem (the zipfs from the binary). That seems wasteful, given the “net/http” library has a handler to serve static files, it’s called http.FileServer(). However, it only works on types implementing the http.FileSystem interface. So that’s what this new httpvfs library does.
If you are making a web server with the net/http library, put the static files in a directory “assets/” and put your files that need embedding in the binary in it. For example “assets/static/css/style.css”. Now use code like this as “main.go”:
package main
import (
"bitbucket.org/mjl/asset"
"bitbucket.org/mjl/httpvfs"
"golang.org/x/tools/godoc/vfs"
"log"
"net/http"
)
func main() {
fs := asset.Fs()
if err := asset.Error(); err != nil {
log.Printf("assets: using local file system...")
fs = vfs.OS("assets")
}
http.Handle("/static/", http.FileServer(httpvfs.New(fs)))
log.Fatal(http.ListenAndServe(":8080", nil))
}
Create a file:
mkdir -p assets/static/css && echo 'body {font-family:sans-serif;}' >assets/static/css
Run this:
go build && ./main
And check if it works:
curl -v http://localhost:8080/static/css/style.css
Now let’s make the binary fat:
(cd assets && zip -r0 ../assets.zip .) && cat assets.zip >>main
Restart the binary:
./main
Notice you won’t get an warning message about using the local file system as you got before. Next, let’s check fetching the file still works:
curl -v http://localhost:8080/static/css/style.css
That’s it. Let me know what you think.