Goはアプリケーションを1バイナリで配布できて楽なのですが、webアプリケーションの場合は大抵静的ファイルを配信する必要があり、これが外部ファイルになってしまいます。CSSとか。
そこで go-bindata を使うとファイルをバイナリに同梱できて便利ですが、これを http.FileServer で配信できたら更に楽になるのでは…と思ってこんな風にしてみました。
http.FileServer
interfaceを実装した AssetFileSystem
と、http.File
interfaceを実装した AssetFile
を適当に定義して、go-bindata で作った Assets()
から取得したデータを配信してやるサンプルです。
ただし、http.serveFile() がindex.htmlへのアクセスをリダイレクトしてくれるという気の効かせ方 をするため、現状は index.html というファイルへのアクセスのみができない(404になる)、という辛い状態です。
実行例
$ go-bindata -prefix=pubic public/...
$ go build
package main
import (
"bytes"
"log"
"net/http"
"os"
"strings"
)
func main() {
http.Handle("/", http.FileServer(AssetFileSystem{}))
log.Fatal(http.ListenAndServe(":3000", nil))
}
type AssetFileSystem struct {
}
type AssetFile struct {
*bytes.Reader
os.FileInfo
}
func (fs AssetFileSystem) Open(name string) (http.File, error) {
path := name
path = strings.TrimLeft(path, "/")
log.Println("open asset", path)
data, err := Asset(path)
if err != nil {
log.Println(err)
return nil, err
}
info, _ := AssetInfo(path)
file := &AssetFile{
bytes.NewReader(data),
info,
}
log.Printf("%#v", file)
return file, nil
}
func (f *AssetFile) Close() error {
return nil
}
func (f *AssetFile) Readdir(count int) ([]os.FileInfo, error) {
return []os.FileInfo{}, nil
}
func (f *AssetFile) Stat() (os.FileInfo, error) {
return f, nil
}