-
Notifications
You must be signed in to change notification settings - Fork 0
/
spahandler.go
66 lines (57 loc) · 1.81 KB
/
spahandler.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
package httputils
import (
"io/fs"
"net/http"
"os"
"path"
"strings"
)
// SpaHandler implements the http.Handler interface, so we can use it
// to respond to HTTP requests. The supplied filesystem is used to deliver
// the static content, which is assumed to be at the root of the filesystem.
type SpaHandler struct {
Fsys fs.FS
}
// NewSpaHandler creates an SpaHandler instance whose static content is provided
// at the root of the supplied filesystem.
func NewSpaHandler(fsys fs.FS) *SpaHandler {
return &SpaHandler{Fsys: fsys}
}
// ServeHTTP inspects the URL path to locate a file within the filesystem
// on the SPA handler. If a file is found, it will be served. If not, the path
// is adjusted to serve the root path, i.e. index.html. This is suitable behavior
// for serving an SPA (single page application).
func (h SpaHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// Treat empty path as '/'
if len(r.URL.Path) == 0 {
r.URL.Path = "/"
}
// ensure we have a clean path
r.URL.Path = path.Clean(r.URL.Path)
// Trim leading '/', unless root path
if len(r.URL.Path) > 1 {
r.URL.Path = strings.TrimPrefix(r.URL.Path, "/")
}
// check whether a file exists at the given path
// - excluding root path which is a synonym for the index file
if r.URL.Path != "/" {
_, err := fs.Stat(h.Fsys, r.URL.Path)
if os.IsNotExist(err) {
// If cannot stat file then use the root index file
r.URL.Path = "/"
} else if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
}
// For root path, check that we have the index file.
if r.URL.Path == "/" {
_, err := fs.Stat(h.Fsys, "index.html")
if err != nil {
http.Error(w, err.Error(), http.StatusNotFound)
return
}
}
// Use http.FileServer to serve the static dir
http.FileServer(http.FS(h.Fsys)).ServeHTTP(w, r)
}