Reputation: 41
I´m trying to serve a SPA with Golang and solving the 404 error became a challenge.
The problem is that it seems to be in a loop, when I try to access the app in the browser, it reloads itself indefinitely.
package main
import (
"log"
"net/http"
"os"
"path/filepath"
"time"
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
"github.com/joho/godotenv"
)
var indexBuffer []byte
func main() {
r := chi.NewRouter()
r.Use(middleware.RequestID)
r.Use(middleware.RealIP)
r.Use(middleware.Logger)
r.Use(middleware.Recoverer)
fs := http.FileServer(http.Dir(os.Getenv("FRONTEND_PATH")))
r.Handle("/app/static/*", http.StripPrefix("/app/static/", fs))
apiRouter := chi.NewRouter()
apiRouter.Get("/cargas", handlerCargas)
r.Mount("/app/api", apiRouter)
r.NotFound(indexHandler)
log.Fatal(http.ListenAndServe(":8000", r))
}
func init() {
err := godotenv.Load()
if err != nil {
log.Fatal("Erro ao ler .env verifique!")
}
indexBuffer, err = os.ReadFile(filepath.Join(os.Getenv("FRONTEND_PATH"), "index.html"))
if err != nil {
log.Fatal("Erro ao tentar bufferizar a index na init().")
}
}
func indexHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/html")
w.Write(indexBuffer)
}
I´m expecting index.html to be served by the indexHandler and the rest of the files be served by the FileServer and errors of page not found be handled by the SPA.
Upvotes: 1
Views: 744
Reputation: 41
I found a solution here
I adapted my code and used the FileServer as below:
// FileServer para SPA
func FileServerSPA(r chi.Router, public string, static string) {
if strings.ContainsAny(public, "{}*") {
panic("FileServer does not permit URL parameters.")
}
root, _ := filepath.Abs(static)
if _, err := os.Stat(root); os.IsNotExist(err) {
panic("Static Documents Directory Not Found")
}
fs := http.StripPrefix(public, http.FileServer(http.Dir(root)))
if public != "/" && public[len(public)-1] != '/' {
r.Get(public, http.RedirectHandler(public+"/", 301).ServeHTTP)
public += "/"
}
r.Get(public+"*", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
file := strings.Replace(r.RequestURI, public, "/", 1)
if _, err := os.Stat(root + file); os.IsNotExist(err) {
http.ServeFile(w, r, path.Join(root, "index.html"))
return
}
fs.ServeHTTP(w, r)
}))
}
and, in main():
// ...
// after all the endpoints of the api
frontendPath := os.Getenv("FRONTEND_PATH")
FileServerSPA(r, "/app", frontendPath)
log.Fatal(http.ListenAndServe(":8000", r))
Hope it helps
Upvotes: 1